写在前面
上一篇主要写了入门级别的SpringMVC程序(http://blog.csdn.net/qq_18242391/article/details/52951825),里面的后台控制器都要实现controller接口或其他控制器接口,才能接受请求,完成相应的逻辑操作。首先来熟悉下其工作流程,这是官方的一个流程图。
同时SpringMVC也提供了用注解来实现相应的逻辑操作,这种强大的数据绑定功能,让其使用起来非常方便,用普通类加注解就可以实现数据收集功能。话不多说,下面来看正文。
正文开始,常用知识点总结
@Controller 这个注解一般用在要请求的类上,也就是相当后端控制器
@RequestMapping 用来定义访问的URL,也就是前面Spring配置文件bean标签中的name属性
@Controller
public class Demo1 {
@RequestMapping(value = "/hello")
public String helloMethod(Model model){
System.out.println("Demo1::helloMethod");
model.addAttribute("message", "SpringMVC注解");
return "/success.jsp";
}
}
这是一个简单的控制器,该类为一个普通类,方法也是随便定义,http请求主要匹配的是@RequestMapping 中的value值,hello后缀可以省略.。 model携封装的是key-value值,接下来看Spring.xml配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
">
<!-- Action控制器 -->
<context:component-scan base-package="cn.itcast.javaee.springmvc.helloannotation"/>
<!-- 基于注解的映射器(可选) -->
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping"/>
<!-- 基于注解的适配器(可选) -->
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"/>
<!-- 视图解析器(可选) -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"/>
</beans>
context:component-scan 表示扫描相应包下的注解,扫描到了,就执行相应类文件。
当然别忘了配置web.xml和写前端jsp页面,这里就不写了,通过浏览器访问到的URL,响应结果如下:
一个Action中,可以写多个类似的业务控制方法
- 通过模块根路径 + 功能子路径 = 访问模块下子功能的路径
@Controller
@RequestMapping(value="/user")
public class UserAction{
@RequestMapping(value="/add")
public String add(Model model) throws Exception{
System.out.println("HelloAction::add()");
model.addAttribute("message","增加用户");
return "/success.jsp";
}
@RequestMapping(value="/find")
public String find(Model model) throws Exception{
System.out.println("HelloAction::find()");
model.addAttribute("message","查询用户");
return "/success.jsp";
}
}
@RequestMapping(value=”/user”) 这个相当于struts2里面的namespace
在业务控制方法中写入普通变量收集参数
可以在业务控制方法中,以参数形式收集客户端参数,springmvc采用的是方法参数形式,如下
@Controller
@RequestMapping(value="/user")
public class UserAction{
@RequestMapping(value="/add")
public String add(Model model,int id,String name,Double sal) throws Exception{
System.out.println("HelloAction::add()");
System.out.println(id + ":" + name + ":" + sal);
model.addAttribute("message","增加用户");
return "/success.jsp";
}
}
限定某个业务控制方法
有时候前端注册的信息只想用POST方式提交表单,或者登陆时只想用GET方式提交,我们可以这样
@Controller
@RequestMapping(value="/user")
public class UserAction{
@RequestMapping(value="/add",method=RequestMethod.POST)
public String add(Model model,int id,String name,double sal) throws Exception{
System.out.println("HelloAction::add()::POST");
System.out.println(id + ":" + name + ":" + sal);
model.addAttribute("message","增加用户");
return "/success.jsp";
}
}
method=RequestMethod.POST 限定了请求只能用POST方式,而不能用GET方式,否则会报如下错误
这里表明了 只能用method中限定的方式访问服务器。 提下,平时我们都不写method,这里GET和POST请求都支持。
传统web参数的支持
我们可以在业务控制方法中书写传统web参数,实现传统的业务请求响应操作
@Controller
@RequestMapping(value="/user")
public class UserAction{
@RequestMapping(value="/add",method=RequestMethod.POST)
public void add(HttpServletRequest request,HttpServletResponse response) throws Exception{
System.out.println("HelloAction::add()::POST");
int id = Integer.parseInt(request.getParameter("id"));
String name = request.getParameter("name");
double sal = Double.parseDouble(request.getParameter("sal"));
System.out.println(id + ":" + name + ":" + sal);
request.getSession().setAttribute("id",id);
request.getSession().setAttribute("name",name);
request.getSession().setAttribute("sal",sal);
response.sendRedirect(request.getContextPath()+"/register.jsp");
}
}
不过这种方式就不推荐了,耦合了,毕竟我们用框架就不提倡用传统的方式来做这种请求操作。
用模型变量收集参数
顺便一提,可以使用@InitBind 来解决字符串转日期类型的问题
<form action="${pageContext.request.contextPath}/user/add.action" method="POST">
编号:<input type="text" name="id" value="${id}"/><br/>
姓名:<input type="text" name="name" value="${name}"/><br/>
薪水:<input type="text" name="sal" value="${sal}"/><br/>
入职时间:<input type="text" name="hiredate" value='<fmt:formatDate value="${hiredate}" type="date"/>'/><br/>
<input type="submit" value="注册"/>
</form>
@Controller
@RequestMapping(value = "/user")
public class UserAction {
@InitBinder
protected void initBinder(HttpServletRequest request,ServletRequestDataBinder binder) throws Exception {
binder.registerCustomEditor(
Date.class,
new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"),true));
}
@RequestMapping(value = "/add", method = RequestMethod.POST)
public String add(int id, String name, double sal, Date hiredate,
Model model) throws Exception {
System.out.println("HelloAction::add()::POST");
model.addAttribute("id", id);
model.addAttribute("name", name);
model.addAttribute("sal", sal);
model.addAttribute("hiredate", hiredate);
return "/register.jsp";
}
}
在业务控制方法中写入bean,model模型收集参数
- 可以在业务控制方法中书写1个模型来收集客户端的参数
- 模型中的属性名必须和客户端参数名一一对应
- 这里说的模型不是Model对象,Model是向视图中封装的数据
@Controller
@RequestMapping(value = "/user")
public class UserAction {
@InitBinder
protected void initBinder(HttpServletRequest request,ServletRequestDataBinder binder) throws Exception {
binder.registerCustomEditor(
Date.class,
new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"),true));
}
@RequestMapping(value = "/add", method = RequestMethod.POST)
public String add(User user,Model model) throws Exception {
System.out.println("HelloAction::add()::POST");
model.addAttribute("user",user);
return "/register.jsp";
}
}
在业务控制方法中收集数组参数
//批量删除用户
@Controller
@RequestMapping(value="/user")
public class UserAction {
@RequestMapping(value="/delete")
public String deleteMethod(int[] ids,Model model) throws Exception{
System.out.println("UserAction::deleteMethod()");
System.out.println("需要删除的id为:");
for(int id : ids){
System.out.print(id+" ");
}
model.addAttribute("message","批量删除成功");
return "/success.jsp";
}
}
//前端
<form action="${pageContext.request.contextPath}/user/delete.action" method="POST">
<table border="2" align="center">
<tr>
<th>编号</th>
<th>姓名</th>
</tr>
<tr>
<td><input type="checkbox" name="ids" value="1"/></td>
<td>哈哈</td>
</tr>
<tr>
<td><input type="checkbox" name="ids" value="2"/></td>
<td>呵呵</td>
</tr>
<tr>
<td><input type="checkbox" name="ids" value="3"/></td>
<td>嘻嘻</td>
</tr>
<tr>
<td><input type="checkbox" name="ids" value="4"/></td>
<td>笨笨</td>
</tr>
<tr>
<td><input type="checkbox" name="ids" value="5"/></td>
<td>聪聪</td>
</tr>
<tr>
<td>
<input type="submit" value="删除"/>
</td>
</tr>
</table>
</form>
这种方式常用于收集checkbox的方式提交的数据
在业务控制方法中收集List参数
批量注册用户
UserAction.java
@Controller
@RequestMapping(value="/user")
public class UserAction {
@RequestMapping(value="/addAll")
public String addAll(Bean bean,Model model) throws Exception{
for(User user : bean.getUserList()){
System.out.println(user.getName()+":"+user.getGender());
}
model.addAttribute("message","批量增加用户成功");
return "/success.jsp";
}
}
Bean.java
public class Bean {
private List<User> userList = new ArrayList<User>();
public Bean(){}
public List<User> getUserList() {
return userList;
}
public void setUserList(List<User> userList) {
this.userList = userList;
}
}
registerAll.java
<form action="${pageContext.request.contextPath}/user/addAll.action" method="POST">
姓名:<input type="text" name="userList[0].name" value="哈哈"/>
性别:<input type="text" name="userList[0].gender" value="男"/>
<hr/>
姓名:<input type="text" name="userList[1].name" value="呵呵"/>
性别:<input type="text" name="userList[1].gender" value="男"/>
<hr/>
姓名:<input type="text" name="userList[2].name" value="嘻嘻"/>
性别:<input type="text" name="userList[2].gender" value="女"/>
<hr/>
<input type="submit" value="批量注册"/>
</form>
结果的转发和重定向
在转发情况下,共享request域对象,会将参数从第一个业务控制方法传入第二个业务控制方法,反之,重定向则不行。
//删除id=10号的用户,再查询用户
@Controller
@RequestMapping(value="/user")
public class UserAction {
@RequestMapping(value="/delete")
public String delete(int id) throws Exception{
System.out.println("删除用户->" + id);
//转发到find()
return "forward:/user/find.action";
//重定向到find()
//return "redirect:/user/find.action";
}
@RequestMapping(value="/find")
public String find(int id) throws Exception{
System.out.println("查询用户->" + id);
return "/success.jsp";
}
}
例子
异步发送表单数据到JavaBean,并响应JSON文本返回
bean2json.jsp
<form>
编号:<input type="text" name="id" value="1"/><br/>
姓名:<input type="text" name="name" value="哈哈"/><br/>
薪水:<input type="text" name="sal" value="5000"/><br/>
<input type="button" value="异步提交注册"/>
</form>
<script type="text/javascript">
$(":button").click(function(){
var url = "${pageContext.request.contextPath}/user/add.action";
var sendData = {
"id":1,
"name":"哈哈",
"sal":5000
};
$.post(url,sendData,function(backData,textStatus,ajax){
alert(ajax.responseText);
});
});
</script>
User.java
public class User {
private Integer id;
private String name;
private Double sal;
public User(){}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Double getSal() {
return sal;
}
public void setSal(Double sal) {
this.sal = sal;
}
}
UserAction.java
@Controller
@RequestMapping(value="/user")
public class UserAction {
@RequestMapping(value="/add")
public @ResponseBody User add(User user) throws Exception{
System.out.println(user.getId()+":"+user.getName()+":"+user.getSal());
return user;
}
}
spring.xml
<!-- Action控制器 -->
<context:component-scan base-package="cn.itcast.javaee.springmvc.app25"/>
<!-- 配适器 -->
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"/>
</list>
</property>
</bean>
可以看到这里配置文件中的适配器主要将控制器中的返回值,转化为json并传给前端响应。
SpringMVC工作流总结
1 客户端发出http请求,只要请求形式符合web.xml文件中配置的*.action的话,就由 DispatcherServlet来处理。
2 DispatcherServlet再将http请求委托给映射器的对象来将http请求交给对应的Action来处理。
3 映射器根据客户的http请求,再对比
4 适配器负责找到Action中业务方法。
5 执行Action中的业务方法,最终返回一个名叫ModelAndView 的对象,其中封装了向视图发送的数据和视图的逻辑名。
6 ModelAndView对象随着响应到DispatcherServlet中了 。
7 这时DispatcherServlet收到了ModelAndView对象,它也不知道视图逻辑名是何意,又得委托一个名叫视图解析器的对象去具体解析ModelAndView对象中的内容。
8 将视图解析器解析后的内容,再次交由DispatcherServlet核心控制器,这时核心控制器再将请求转发到具体的视图页面,取出数据,再显示给用户。
最后
从前面的例子可以看见,我们在使用springmvc的注解时非常灵活,通常可以自己定制自己的业务控制器,不比Struts2,必须用特定接口和规范,来完成业务逻辑,当然SpringMVC的知识点还有很多,这只是微不足道的冰山一角,以后知道了再继续补充。 咳咳,由于本人能力有限,还只是刚刚学习,很多地方不懂,总结只能写这些最基础的东西,相信通过不断的学习,总有一天能写出有技术含量的文章的,哈哈,人生还是得乐观点,作为一名伟大的程序员,这是一份值得骄傲的事业,要努力干下去,让代码将梦想照进现实哈。上张我最喜欢的naruto作为文章的结束吧。。。。