Struts学习(二)
1.前言
今天写了一个简单的项目,就是用Struts框架进行表单的校验,防止表单的重复提交,外加用原来的过滤器技术处理全局乱码问题.深刻体会到了框架带来的便捷!
2.步骤
2.1 定义3个Enum枚举类
为了程序的可扩展性,定义3个Enum枚举类,Gender类表示用户性别,Preference表示用户偏好,City表示用户所在城市,这样在注册页面编码时就不用硬编码了,迭代枚举类添加相应的标签即可.枚举类(Preference)程序如下:
package cn.itcast.web.global;
public enum Preference {
SING("sing","唱歌"),DANCE("dance","舞蹈"),FOOTBALL("football","足球"),BASKETBALL("basketball","篮球");
private String name;
private String value;
private Preference(String name,String value){
this.name = name;
this.value = value;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
2.2 编写JSP注册表单
JSP注册表单中使用了HTML标签库,这是Apache提供的Stuts标签库,其中的form标签会自动添加提交方式为post,而且当Session域中有随机数时,他会自动添加一个包含有随机数的hidden标签提交.在该表单中使用了枚举类的values()方法用于获得枚举类中的所有元素,在使用Jstl的foreach标签进行迭代,动态创建出所需的标签.JSP注册页面程序如下:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@taglib uri="http://struts.apache.org/tags-html" prefix="html" %>
<%@page import="cn.itcast.web.global.Gender" %>
<%@page import="cn.itcast.web.global.City" %>
<%@page import="cn.itcast.web.global.Preference" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>注册</title>
</head>
<body style="text-align: center">
<html:form action="/Register">
<table border="1" width="60%">
<tr>
<td>用户名</td>
<td>
<html:text property="username" />
</td>
<td>
<html:errors property="username"/>
</td>
</tr>
<tr>
<td>密码</td>
<td>
<html:password property="password" redisplay="false"/>
</td>
<td>
<html:errors property="password"/>
</td>
</tr>
<tr>
<td>确认密码</td>
<td>
<html:password property="password2" redisplay="false"/>
</td>
<td>
<html:errors property="password2"/>
</td>
</tr>
<tr>
<td>性别</td>
<td>
<!--
<c:forEach var="g" items="<%=Gender.values() %>">
<input type="radio" name="gender" value="${g.name }"/>${g.value }
</c:forEach>
-->
<c:forEach var="g" items="<%=Gender.values() %>">
<html:radio property="gender" value="${g.name }">${g.value }</html:radio>
</c:forEach>
</td>
<td>
<html:errors property="gender"/>
</td>
</tr>
<tr>
<td>生日</td>
<td>
<html:text property="birthday" />
</td>
<td>
<html:errors property="birthday"/>
</td>
</tr>
<tr>
<td>城市</td>
<td>
<!--
<select name="city">
<c:forEach var="city" items="<%=City.values() %>">
<option value="${city.name }">${city.value }</option>
</c:forEach>
</select>
-->
<html:select property="city">
<c:forEach var="city" items="<%=City.values() %>">
<html:option value="${city.name }">${city.value }</html:option>
</c:forEach>
</html:select>
</td>
<td>
<html:errors property="city"/>
</td>
</tr>
<tr>
<td>爱好</td>
<td>
<!--
<c:forEach var="pre" items="<%=Preference.values() %>">
<input type="checkbox" name="preference" value="${pre.name }"/>${pre.value }
</c:forEach>
-->
<c:forEach var="pre" items="<%=Preference.values() %>">
<html:multibox property="preference" value="${pre.name }"/>${pre.value }
</c:forEach>
</td>
<td>
<html:errors property="preference"/>
</td>
</tr>
<tr>
<td>
<input type="reset" value="重置"/>
</td>
<td>
<input type="submit" value="注册"/>
</td>
</tr>
</table>
</html:form>
</body>
</html>
2.3 配置struts-config.xml 和 web.xml文件
struts-config.xml文件没有太大的变化,定义一个FormBean对象,一个用于转发的Action对象,一个用于处理表单的Action对象和一个资源文件对象.配置如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts-config PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 1.3//EN"
"http://struts.apache.org/dtds/struts-config_1_3.dtd">
<struts-config>
<form-beans>
<form-bean name="UserFormBean" type="cn.itcast.web.formBean.UserFormBean"></form-bean>
</form-beans>
<action-mappings>
<action path="/Register"
type="cn.itcast.web.action.Register"
scope="request"
input="/WEB-INF/jsp/register.jsp"
name="UserFormBean"
validate="true"
>
<forward name="success" path="/success.jsp"></forward>
<forward name="message" path="/message.jsp"></forward>
</action>
<action path="/RegisterUI" type="cn.itcast.web.action.RegisterUIAction">
<forward name="register" path="/WEB-INF/jsp/register.jsp"></forward>
</action>
</action-mappings>
<!-- 配置文件,用ActionMessage可以用到里面的数据 -->
<message-resources parameter="config"></message-resources>
</struts-config>
web.xml文件定义了一个全局乱码过滤器CharacterEncodingFilter,一个处理全局类型转换的监听器WebInitListener,和一个Apache提供的一个核心类ActionServlet.配置如下:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
<display-name>struts13</display-name>
<listener>
<listener-class>cn.itcast.web.listener.WebInitListener</listener-class>
</listener>
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>cn.itcast.web.filter.CharacterEncodingFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<servlet>
<servlet-name>ActionServlet</servlet-name>
<servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
<init-param>
<param-name>config</param-name>
<param-value>/WEB-INF/struts-config.xml</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>ActionServlet</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
</web-app>
2.4 监听器和过滤器
监听器WebInitListener用于处理类型转换问题,该监听器实现ServletContextListener接口.并在配置时用于处理全局,所以当服务器开启时,监听器就开始工作了,当有类型转化的时候,监听器就会工作.程序如下:
package cn.itcast.web.listener;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import org.apache.commons.beanutils.ConvertUtils;
import org.apache.commons.beanutils.Converter;
import cn.itcast.web.global.City;
import cn.itcast.web.global.Gender;
import cn.itcast.web.global.Preference;
public class WebInitListener implements ServletContextListener {
@Override
public void contextDestroyed(ServletContextEvent arg0) {
// TODO Auto-generated method stub
}
@Override
public void contextInitialized(ServletContextEvent arg0) {
ConvertUtils.register(new Converter(){
@Override
public Object convert(Class type, Object obj) {
if(obj == null){
return null;
}
if(obj instanceof String){
String str = (String)obj;
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
try {
return sdf.parse(str);
} catch (ParseException e) {
e.printStackTrace();
throw new RuntimeException("输入的格式不正确");
}
}else{
throw new RuntimeException("输入的不是String类型");
}
}
}, Date.class);
ConvertUtils.register(new Converter(){
public Object convert(Class type, Object obj) {
if(obj == null){
return null;
}
if(obj instanceof String){
String str = (String)obj;
return Gender.valueOf(str.toUpperCase());
}
return null;
}
}, Gender.class);
ConvertUtils.register(new Converter(){
public Object convert(Class type, Object obj) {
if(obj == null){
return null;
}
if(obj instanceof String){
String str = (String)obj;
return City.valueOf(str.toUpperCase());
}
return null;
}
}, City.class);
ConvertUtils.register(new Converter(){
public Object convert(Class type, Object obj) {
if(obj == null){
return null;
}
String[] params = (String[])obj;
Preference[] pres = new Preference[params.length];
int index = 0;
for(String str : params){
pres[index++] = Preference.valueOf(str.toUpperCase());
}
return pres;
}
}, Preference[].class);
}
}
过滤器没什么好说的,实现Filter接口,在dofilter方法中处理乱码就可以了.程序如下:
package cn.itcast.web.filter;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class CharacterEncodingFilter implements Filter {
@Override
public void destroy() {
}
@Override
public void doFilter(ServletRequest req, ServletResponse resp,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp;
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");
response.setHeader("text/html", "charset=UTF-8");
chain.doFilter(request, response);
}
@Override
public void init(FilterConfig arg0) throws ServletException {
}
}
2.5 FormBean对象处理表单校验
在这里定义一个UserFormBean类处理表单校验,该类继承ActionForm类,在struts-config.xml中映射一个Action是将其validate属性设置为true是,就会执行FormBean中的validate方法.当返回值为null是,说明表单没问题,提交.当返回值为ActionErrors对象是,说明表单提交失败,并且该对象中封装了错误信息,当然了,这些数据是自己加进去的.程序如下:
package cn.itcast.web.formBean;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import javax.servlet.http.HttpServletRequest;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionMessage;
import cn.itcast.web.global.City;
import cn.itcast.web.global.Gender;
import cn.itcast.web.global.Preference;
public class UserFormBean extends ActionForm{
private String id;
private String username;
private String password;
private String password2;
private String gender;
private String birthday;
private String city;
private String[] preference;
@Override
public ActionErrors validate(ActionMapping mapping,
HttpServletRequest request) {
ActionErrors errors = new ActionErrors();
if(isEmpty(username)){
errors.add("username",new ActionMessage("errors.username.isempty"));
}else{
if(!username.matches("\\w{3,9}")){
errors.add("username",new ActionMessage("errors.username.notmatch"));
}
}
if(isEmpty(password)){
errors.add("password",new ActionMessage("errors.password.isempty"));
}else{
if(!password.matches("\\w{3,9}")){
errors.add("password",new ActionMessage("errors.password.notmatch"));
}
}
if(!isEmpty(password2) && !password2.equals(password)){
errors.add("password2",new ActionMessage("errors.password2.notmatch"));
}
if(!isEmpty(birthday)){
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
try {
sdf.parse(birthday);
} catch (ParseException e) {
errors.add("birthday",new ActionMessage("errors.birthday.notmatch"));
}
}
if(isEmpty(gender)){
errors.add("gender",new ActionMessage("errors.gender.isempty"));
}else{
try{
Gender.valueOf(gender.toUpperCase());
}catch(Exception e){
errors.add("gender",new ActionMessage("errors.gender.notmatch"));
}
}
if(isEmpty(city)){
errors.add("city",new ActionMessage("errors.city.isempty"));
}else{
try{
City.valueOf(city.toUpperCase());
}catch(Exception e){
errors.add("city",new ActionMessage("errors.city.notmatch"));
}
}
if(preference != null && preference.length>0){
try{
for(String pre : preference){
Preference.valueOf(pre.toUpperCase());
}
}catch(Exception e){
errors.add("preference",new ActionMessage("errors.preference.notexist"));
}
}
return errors;
}
public boolean isEmpty(String name){
if(name == null || name.trim().equals("")){
return true;
}
return false;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getPassword2() {
return password2;
}
public void setPassword2(String password2) {
this.password2 = password2;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public String getBirthday() {
return birthday;
}
public void setBirthday(String birthday) {
this.birthday = birthday;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String[] getPreference() {
return preference;
}
public void setPreference(String[] preference) {
this.preference = preference;
}
}
3.总结
struts这种框架还是要实践啊!表单校验方面确实比以前简单,明天继续!