接著上一篇javaWEB簡單商城項目(五),這一篇使用BeanUtil框架寫注冊頁面,並且學習基於Annotation的驗證.
注冊思路按照下圖,按照上一篇的MVC設計,我們的UserServlet只負責處理請求,BaseServlet只負責調用相應處理該請求的方法
首先建立一個register.jsp的注冊頁面,很簡單,只需要用戶名,密碼,昵稱即可,當然密碼驗證是需要你在服務器端來處理的,後面的Annotation就是做這個的
<%@ page="" contenttype="text/html;charset=UTF-8" language="java">
<%@ page="" contenttype="text/html;charset=UTF-8" language="java">
首先對user.do?method=register這個請求相應的話,我們需要在UserServlet中寫一個register專門用來顯示界面的
/**
* 跳轉到注冊用戶界面
*/
public String register(HttpServletRequest req, HttpServletResponse resp){
//直接返回當前頁面,其他的由BaseServlet來處理
return "user/register.jsp";
}
當我們點submit的時候提交的action是user.do?method=add,因此我們需要在UserSerclet中寫一個add方法來添加用戶,並且再添加用戶後跳轉到用戶列表list
/**
* 接收注冊消息,添加用戶
* @return 返回用戶列表
*/
public String add(HttpServletRequest req, HttpServletResponse resp){
String username = req.getParameter("username");
String password = req.getParameter("password");
String nickname = req.getParameter("nickname");
User u = new User();
u.setUsername(username);
u.setPassword(password);
u.setNickname(nickname);
/**
* 通過dao工廠來生產dao,工廠有緩存效果,這裡之前已經用了依賴注入,所以這個不需要了
*/
// UserDao userDao = (UserDao) PropertiesFactory.getInstance().createDao("UserDao");
userDao.add(u);
//這裡客戶端跳轉,如果是服務器端,則刷新後會再次提交
return "client:user.do?method=list";
}
這裡的返回方式采用客戶端跳轉,因為跳轉到用戶列表list的時候,我們是需要浏覽器的鏈接地址改變的.
從上面代碼中我們可以看到,當我們接收參數的時候需要先獲取參數,然後再一個一個的set,如果我們將來要在User中增加一個屬性,那麼改起來則是很費勁的,所以我們需要利用反射做一個統一的部署,也就是使用BeanUtil.
* 第一步是引入包
* 第二步參考官方文檔使用,為了方便,我們單寫一個RequestUtil,在裡面寫上處理方法.
import org.apache.commons.beanutils.BeanUtils;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.InvocationTargetException;
import java.util.Map;
import java.util.Set;
/**
* Created by nl101 on 2016/3/5.
*/
public class RequestUtil {
/**
* 根據傳來的clz,自動創建其實例,並調用其set方法把req裡面的參數設置進去
* @param clz 需要創建實例的class
* @param req 包含的參數
* @return 返回創建好的實例
*/
public static Object setParams(Class clz,HttpServletRequest req){
Map maps = req.getParameterMap();//獲取參數的map集合
Set keys = maps.keySet();//獲取key的集合
Object o = null;
try {
o = clz.newInstance();//獲取實例
//循環遍歷參數
for (String key:keys){
String[] arrs = maps.get(key);//獲取參數值數組
if (arrs.length>1){//如果數組長度大於1,說明多個值
BeanUtils.copyProperty(o,key,arrs);
}else {//如果數組是不大於1,則設置單個值
BeanUtils.copyProperty(o,key,arrs[0]);
}
}
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return o;//返回創建好的對象
}
}
寫好後我們的UserServlet的add方法該怎麼修改呢?
/**
* 接收注冊消息,添加用戶
* @return 返回用戶列表
*/
public String add(HttpServletRequest req, HttpServletResponse resp){
//直接調用其方法創建對象即可
User u = (User) RequestUtil.setParams(User.class,req);
userDao.add(u);
//這裡客戶端跳轉,如果是服務器端,則刷新後再次提交
return "client:user.do?method=list";
}
是不是比起沒使用前的代碼大大減少了代碼量哈.
BeanUtil有一些類型是解析不了的,也就是沒法直接設置參數進去.比如日期Date類,日期類的格式太多了,因此BeanUtil不知道該用哪個,這個時候我們需要手動寫轉換器,然後添加到BeanUtil的規則中.
轉換器要實現org.apache.commons.beanutils.Converter接口,並重寫convert方法
import org.apache.commons.beanutils.Converter;
import java.text.ParseException;
import java.text.SimpleDateFormat;
/**
* Created by nl101 on 2016/3/5.
*/
public class DateConvert implements Converter {
private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
/**
* 日期轉換器,把日期解析成專用格式
* @param aClass 使用該類來解析
* @param o 需要解析的參數
* @return 返回解析後的Date實例
*/
@Override
public Object convert(Class aClass, Object o) {
try {
if (o!=null && !"".equals((String)o)){//值不為空則轉換
return sdf.parse((String)o);
}
} catch (ParseException e) {
System.out.println("日期轉換失敗");
e.printStackTrace();
}
return null;//如果轉換失敗則返回null
}
}
那麼使用這個轉換器
User u = new User();
ConvertUtils.register(new DateConvert(),Date.class);//注冊轉換器,那麼當BeanUtil遇到Date為set的參數的時候會調用這個轉換器
try {
BeanUtils.copyProperty(u,"date","1999-10-1");
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
System.out.println(u.getDate().toString());
這樣就完成了一個自定義轉換器.
當用戶信息輸入到讀取到服務器端的時候要進行一定的驗證是否合法才能存入數據庫,否則重新填寫.
變量上面的Annotation有其檢查類型,為NOTNULL,就檢查其是否為NULL,errsMsg則是提示信息,也就是為NULL要顯示的信息.
public enum ValidType {
NOTNULL,LENGTH,NUM;
}
接下來是定義Annotation,這個很簡單,就按照圖片上面的來
//這個說明指的是當前Annotation在運行的時候
@Retention(RetentionPolicy.RUNTIME)
public @interface ValidCheck {
public ValidType type();//表明錯誤類型
public String errsMsg();//表明錯誤提示
}
然後因為這是對請求參數的驗證,所以可以卸載RequestUtil這個類中
/**
* 進行參數檢查,檢查是否符合定義的規則
* @param clz 要檢查的參數對應的類
* @param req 參數信息
* @return 符合返回true
*/
public static boolean isChecked(Class clz,HttpServletRequest req){
Field[] fields = clz.getDeclaredFields();//獲得全部的屬性
boolean isValid = true;//表示檢查結果
Map errors = new HashMap<>();//存入錯誤信息
req.setAttribute("errors",errors);//把其設置到req中,這樣jsp可以獲取到相關值
//開始遍歷
for (Field f:fields){
if (f.isAnnotationPresent(ValidCheck.class)){//如果是該Annotition
ValidType type = f.getAnnotation(ValidCheck.class).type();//獲取type
String msg = f.getAnnotation(ValidCheck.class).errsMsg();//獲取msg
if (type == ValidType.NOTNULL){//為NOTNULL,執行指定函數
if (!isNotNull(f.getName(),req)){
isValid = false;
errors.put(f.getName(),msg);//把錯誤存入其中
}
}
}
}
return isValid;
}
/**
* 判斷是否為空
* @param field 要判斷的屬性名字
* @param req 參數集合
* @return true不為空
*/
private static boolean isNotNull(String field,HttpServletRequest req){
String temp = req.getParameter(field);
if (temp==null || "".equals(temp.trim())){
return false;
}
return true;
}
調用很簡單,我們在進行數據庫操作前進行檢查即可
/**
* 接收注冊消息,添加用戶
* @return 返回用戶列表
*/
public String add(HttpServletRequest req, HttpServletResponse resp){
boolean isValid = RequestUtil.isChecked(User.class,req);//進行判斷
if (!isValid){
return "user/register.jsp";
}
ConvertUtils.register(new DateConvert(),Date.class);//注冊轉換器,那麼當BeanUtil遇到Date為set的參數的時候會調用這個轉換器
User u = (User) RequestUtil.setParams(User.class,req);
userDao.add(u);
//這裡客戶端跳轉,如果是服務器端,則刷新後再次提交
return "client:user.do?method=list";
}
jsp頁面設置有兩個要求,提交後才進行判斷,然後不符合則顯示信息,而且還要保存之前填寫的數據,把其自動填寫進去.這個時候EL的
<%@ page="" contenttype="text/html;charset=UTF-8" language="java">
<[email protected] prefix="c" uri="http://java.sun.com/jstl/core_rt">
<%@ page="" contenttype="text/html;charset=UTF-8" language="java"><[email protected] prefix="c" uri="http://java.sun.com/jstl/core_rt">
框架搭的差不多了,下一篇開始逐漸完善每一步,用博客來記錄心得體會