1 参数绑定与值的传递
页面请求发起的时候,如何把数据传给 Action , 在 Action 中如何把模型数据进行传递
1) 在Action 的方法的形参上,可以使用如下的形参
HttpServletRequest
HttpServletResponse
HttpSession
Model //接口 interface org.springframework.ui.Model
ModelMap // org.springframework.ui.ModelMap extends java.util.LinkedHashMap
Map<String,Object> //普通的Map也可以
不能传 ServletContext 对象, 可以用 request.getServletContext() 这个方法得到
例子 用户登录,登录以后转到 main.jsp , 并显示出用户信息 (模型数据)
登录页: WebRoot下的 login.jsp:
<form action="login" method="post" >
账号: <input type="text" name="userName" />
密码: <input type="text" name="password" />
<input type="submit" value="登录"/>
</form>
Action
@RequestMapping(value="/login")
public String login(HttpServletRequest request,Model model,Map<String,Object> map,ModelMap modelMap){
String userName=request.getParameter("userName");
String password=request.getParameter("password");
UserInfo user=dao.getLoginUser(userName,password);
//request.setAttribute("user", user);
model.addAttribute("user",user);
map.put("map_msg", "用户登录成功,用map传的消息");
modelMap.addAttribute("modelmap_msg","这是用modelmap传的信息");
return "main"; //=WEB-INF/jsp/main.jsp
}
main.jsp
用户信息:
<hr />
账号: ${user.userName }
密码: ${user.password }
学校: ${user.school }
<hr />
用map传的信息: ${map_msg }
<hr />
用 modelMap传的信息: ${modelmap_msg }
2) 可以使用简单类型
比如上面的登录功能可以写成
@RequestMapping(value="/login")
public String login(String userName,String password,Model model){
UserInfo user=dao.getLoginUser(userName,password);
System.out.println(userName+":"+password);
model.addAttribute("user",user);
return "main";
}
例子
@RequestMapping(value="/test")
public void test
(
String userName,
@RequestParam("password") String pwd,
@RequestParam(value="age",required=true ) int age,
@RequestParam(value="school",defaultValue="初中毕业") String school
)
{
System.out.println("userName="+userName);
System.out.println("password="+pwd);
System.out.println("age="+age);
System.out.println("school="+school);
}
访问这个方法
http://localhost:8080/springmvc-01/test?userName=admin&password=987&age=987&school=huaixia
3) 可以使用pojo类型 (bean)
添加功能:
创建 web-root 下的 user_add.jsp:
<form action="user_add" method="post" >
账号: <input type="text" name="userName" />
密码: <input type="text" name="password" />
备注: <input type="text" name="note" />
学校: <input type="text" name="school" />
<input type="submit" value="提交"/>
</form>
${msg }
UserAction:
@RequestMapping(value="/user_add")
public String addUser(UserInfo user,Model m){
System.out.println(user);
dao.addUser(user);
m.addAttribute("msg", "用户添加成功");
return "user_add";
}
这里有中文乱码问题
可以用乱码的过滤器处理
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>杠*</url-pattern>
</filter-mapping>
要注意,上面的过滤器,只有请求是post的方式时才可以
要想让get请求和post请求的编码处理方式一样 ,在 tomcat 安装目录下: conf/server.xml
加上
useBodyEncodingForURI="true"
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" useBodyEncodingForURI="true" /> //加上这句,注意true两边要有双引号
关于日期类型的处理
1 在UserInfo中加一个日期类型的字段 private Date birthday;
2 数据库里也可以加入 datetime 类型的 birthday
在用户添加页面 user_add.jsp ,再加一个输入框
生日:<input type="text" name="birthday" />
然后运行,添加用户,输入生日 2005-10-25 提交,发现出现了400错误
原因就是因为springmvc不知道怎么处理(我们输入的)日期格式
处理方法
方式一 在实体类 UserInfo 上加日期格式化注解
@DateTimeFormat(pattern="yyyy-MM-dd") //简单,有效,可以传空值
private Date birthday;
方式二 在控制器 UserAction 中添加一段日期处理代码
@InitBinder
public void initBinder(WebDataBinder binder){
SimpleDateFormat dateFormat=new SimpleDateFormat("yyyy-MM-dd");
dateFormat.setLenient(false);
binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, true)); //这里的true这个参数,表示可传入空值
}
这种方式的控制粒度更细一些(因为若是在实体类中加,若是这个实体类使用的多,那格式需求就不一样,所以有时候就不合适了)
4) 可以使用包装类型的 pojo
例子:
public class UserInfoCustom {
UserInfo user; //用户信息
private String petName; //宠物的名字
private String petAddress; //宠物的家
}
user_add.jsp:
<form action="user_add" method="get">
用户信息
<hr>
账号:<input type="text" name="user.userName" />
密码:<input type="text" name="user.password" />
学校:<input type="text" name="user.school" />
生日:<input type="text" name="user.birthday" /> <br>
宠物信息
<hr>
宠物名:<input type="text" name="petName" />
宠物家:<input type="text" name="petAddress" />
<input type="submit" value="提交" />
${msg }
</form>
//控制层 UserAction:
@RequestMapping(value="/user_add")
public String addUser(UserInfoCustom userPet,Model m ){ //这就是包装的 pojo
System.out.println(userPet);
//....进行数据库操作
m.addAttribute("msg", "用户添加成功");
return "user_add";
}
5) 数组类型 比如批量删除
userlist.jsp
<form action="delete_all" method="post">
<table border="1" width="500">
<c:forEach var="user" items="${userList}" >
<tr>
<td><input type="checkbox" name="ids" value="${user.id }"> </td>
<td>${user.id }</td>
<td>${user.userName }</td>
<td>${user.password }</td>
<td>${user.school }</td>
<td> <a href="update_user?id=${user.id }" >修改</a></td>
</tr>
</c:forEach>
</table>
<input type="submit" value="删除所选" />
</form>
@RequestMapping("/delete_all")
public String deleteUsers(Integer [] ids){
for(int id:ids){
System.out.println(id);
dao.delUserById(id);
}
return "forward:search_all_user";
}
6) List类型 (比如批量更新)
(1) 建一个类
public class UserInfoListCustom {
private List<UserInfo> userList;
... get set ...
}
(2) Action 中
@RequestMapping("/update_all")
public String updateAllUser(UserInfoListCustom ul ){
List<UserInfo> userList=ul.getUserList();
for(UserInfo u:userList){
System.out.println(u);
dao.updateUser(u);
}
return "forward:search_all_user";
}
(3) user_manage.jsp
<form action="update_all" method="post">
<table border="1" width="500">
<c:forEach var="user" items="${userList}" varStatus="st" >
<tr>
<td><input type="text" name="userList[${st.index }].id" value="${user.id }" /> </td>
<td><input type="text" name="userList[${st.index }].userName" value="${user.userName }" /> </td>
<td><input type="text" name="userList[${st.index }].password" value="${user.password }" /></td>
<td><input type="text" name="userList[${st.index }].school" value="${user.school }" /></td>
</tr>
</c:forEach>
</table>
<input type="submit" value="批量修改" />
</form>
2 数据的回显
<form action="user_add" method="get">
账号:<input type="text" name="userName" value="${user.userName}" />
密码:<input type="text" name="password" value="${user.password}" />
学校:<input type="text" name="school" value="${user.school}" />
<input type="submit" value="提交" />
${msg }
</form>
例一 可以用 Model 回传数据
@RequestMapping(value="/user_add")
public String addUser(UserInfo user,Model m ){
dao.addUser(user);
m.addAttribute("user",user); //用这样的方式回传数据
m.addAttribute("msg", "用户添加成功");
return "user_add";
}
例二 可以用 @ModelAttribute("user") 这样的方式回传数据
@RequestMapping(value="/user_add")
public String addUser(@ModelAttribute("user") UserInfo user){
dao.addUser(user);
user.setUserName("这是改过后的名称");
return "user_add";
}
例三 对于普通类型的参数 (也是用model回传)
@RequestMapping(value="/login")
public String login( String userName,String password,Model model){
UserInfo user=dao.getLoginUser(userName,password);
//...数据库查询
model.addAttribute("userName",userName);
model.addAttribute("password",password);
model.addAttribute("msg" ,"登录失败");
return "login";
}
login.jsp
<form action="login" method="post" >
账号: <input type="text" name="userName" value="${userName}" />
密码: <input type="text" name="password" value="${password }" />
<input type="submit" value="登录"/>
</form>
${msg}
例四 使用Spring提供的标签
user_add.jsp
<%@ taglib uri="http://www.springframework.org/tags/form" prefix="x" %>
<x:form action="user_add" method="post" >
账号:<x:input path="userName" />
密码:<x:input path="password" />
学校:<x:input path="school" />
<input type="submit" value="提交" />
</x:form>
如果这时直接访问这个页面,将出错
No WebApplicationContext found: no ContextLoaderListener registered
因为没有初始化Spring环境 ,要在web.xml中加入相关的配置
初始化 spring 环境
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc-config.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
// 这是把所有的请求交给 spring 核心控制器 处理
<servlet>
<servlet-name>SpringAAA</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:springmvc-config.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>SpringAAA</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
再运行
Neither BindingResult nor plain target object for bean name 'command' available as request attribute
要在表单属性上加上 commandName="user" 或 modelAttribute="user" 如下:
<x:form action="user_add" method="post" modelAttribute="user" >
再运行
nor plain target object for bean name 'user' available as request attribute
要如下处理,先写一个方法,通过这个方法转到目标页面
@RequestMapping(value="/user_add",method=RequestMethod.POST)
public String addUser(@ModelAttribute("user") UserInfo user){
dao.addUser(user);
user.setUserName("这是改过后的名称");
return "user_add";
}
@RequestMapping(value="/user_add",method=RequestMethod.GET)
public String gotoAddUser(@ModelAttribute("user") UserInfo user){
return "user_add";
}
测试:访问:http://localhost:8080/SpringMVC-04/user/add_user
3 异常处理
1) 在action中进行处理 (局部)
@ExceptionHandler(value=Exception.class)
public String exceptionProccess(Exception ex,HttpServletRequest request){
request.setAttribute("ex", ex);
return "error_process";
}
error_process.jsp
<h1>对不起,出错了</h1>
${ex.message }
以后这个action中的任何方法执行如果发生异常,就会转到这个方法 ( exceptionProccess() ) 上
例子:自定义异常类
public class MyException extends Exception
{
private String msg;
public MyException(String msg){
super(msg); //把异常信息传给父类的构造函数
this.msg=msg;
}
public void showErrorMsg(){
System.err.println(new Date()+":"+this.msg);
System.out.println("日记已记录...");
}
}
UserAction:
@ExceptionHandler(value=MyException.class)
public String exceptionProccess(MyException ex,HttpServletRequest request){
request.setAttribute("ex", ex);
ex.showErrorMsg();
return "error_process";
}
@RequestMapping(value="/login")
public String login( String userName,String password,Model model) throws MyException{
UserInfo user=dao.getLoginUser(userName,password);
if(!"周杰伦".equals(userName)){
throw new MyException("登录的人物不是周杰伦");
}
model.addAttribute("userName",userName);
model.addAttribute("password",password);
return "login";
}
2) 全局异常处理
在配置文件 springmvc-config.xml 中加上
<bean id="exceptionResolver" class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="exceptionMappings">
<props>
<prop key="cat.beans.MyException">error_process_1</prop> //注意,这里的 error_process_1 是受前缀和后缀影响的
<prop key="java.lang.Exception">error_process_2</prop>
<prop key="java.lang.SQLException">error_process_3</prop>
</props>
</property>
</bean>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" >
<property name="prefix" value="/" />
<property name="suffix" value=".jsp" />
</bean>