相关文章推荐
叛逆的小蝌蚪  ·  python - Audio and ...·  1 年前    · 
年轻有为的生菜  ·  Atlassian In ...·  1 年前    · 
坚韧的丝瓜  ·  BluetoothAdapter.GetPr ...·  1 年前    · 
  • 控制器将模型数据在视图(View)中展示
    web中模型无法将数据直接在视图上显示,需要通过控制器完成。如果在C/S应用中模型是可以将数据在视图中展示的。

  • 控制器将视图response响应给用户
    通过视图展示给用户要的数据或处理结果。

  • DispatcherServlet 收到请求调用 HandlerMapping 处理器映射器.
  • 处理器映射器找到具体的处理器,生成处理器对象及处理器拦截器(如果有则生成)一并返回给 DispatcherServlet .
  • DispatcherServlet 调用 HandlerAdapter 处理器适配器. HandlerAdapter 经过适配调用具体的处理器(Controller,也叫后端控制器). Controller 执行完成返回 ModelAndView . HandlerAdapter controller 执行结果 ModelAndView 返回给 DispatcherServlet . DispatcherServlet ModelAndView 传给 ViewReslover 视图解析器. ViewReslover 解析后返回具体 View . DispatcherServlet 根据View进行渲染视图(即将模型数据填充至视图中)。 DispatcherServlet 响应用户

    组件说明:

    ++以下组件通常使用框架提供实现:++

    DispatcherServlet :作为前端控制器,整个流程控制的中心,控制其它组件执行,统一调度,降低组件之间的耦合性,提高每个组件的扩展性。

    HandlerMapping :通过扩展处理器映射器实现不同的映射方式,例如:配置文件方式,实现接口方式,注解方式等。

    HandlAdapter :通过扩展处理器适配器,支持更多类型的处理器。

    ViewResolver :通过扩展视图解析器,支持更多类型的视图解析,例如:jsp、freemarker、pdf、excel等。

    ++下边两个组件通常情况下需要开发++:

    Handler :处理器,即后端控制器用controller表示。

    View :视图,即展示给用户的界面,视图中通常需要标签语言展示模型数据。

    4.开发环境准备

    本教程使用Eclipse+tomcat7开发

    详细参考“Eclipse开发环境配置-indigo.docx”文档

    5.第一个springmvc工程

    第一步:建立一个Web项目

    在eclipse下创建动态web工程springmvc_01。

    第二步:导入spring3.1.4的jar包

    <servlet>
        <servlet-name>springmvc</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:springmvc-servlet.xml</param-value>
        </init-param>
        // 表示servlet随服务启动
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>springmvc</servlet-name>
        // 以.action结尾的请求交给DispatcherServlet处理
        <url-pattern>*.action</url-pattern>
    </servlet-mapping>
    

    load-on-startup:表示servlet随服务启动;

    url-pattern:*.action的请交给DispatcherServlet处理。

    contextConfigLocation:指定springmvc配置的加载位置,如果不指定则默认加载WEB-INF/[DispatcherServlet 的Servlet 名字]-servlet.xml。

    第四步:springmvc配置文件

    Springmvc默认加载WEB-INF/[前端控制器的名字]-servlet.xml,也可以在前端控制器定义处指定加载的配置文件,如下:

    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:springmvc-servlet.xml</param-value>
    </init-param>
    

    如上代码,通过contextConfigLocation加载classpath下的springmvc-servlet.xml配置文件,配置文件名称可以不限定[前端控制器的名字]-servlet.xml。

    第五步:配置处理器映射器

    在springmvc-servlet.xml文件配置如下:

    <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"
        xmlns:context="http://www.springframework.org/schema/context"
        xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
        xsi:schemaLocation="http://www.springframework.org/schema/beans 
            http://www.springframework.org/schema/beans/spring-beans-3.1.xsd 
            http://www.springframework.org/schema/mvc 
            http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd 
            http://www.springframework.org/schema/context 
            http://www.springframework.org/schema/context/spring-context-3.1.xsd 
            http://www.springframework.org/schema/aop 
            http://www.springframework.org/schema/aop/spring-aop-3.1.xsd 
            http://www.springframework.org/schema/tx 
            http://www.springframework.org/schema/tx/spring-tx-3.1.xsd ">
        <!-- 处理器映射器 -->
        <!-- 根据bean的name进行查找Handler 将action的url配置在bean的name中 -->
        <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" />
    

    BeanNameUrlHandlerMapping:表示将定义的Bean名字作为请求的url,需要将编写的controller在spring容器中进行配置,且指定bean的name为请求的url,且必须以.action结尾。

    第六步:配置处理器适配器

    在springmvc-servlet.xml文件配置如下:

    <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
    

    SimpleControllerHandlerAdapter:即简单控制器处理适配器,所有实现了org.springframework.web.servlet.mvc.Controller 接口的Bean作为Springmvc的后端控制器。

    第七步:配置视图解析器

    在springmvc-servlet.xml文件配置如下:

    <!-- ViewResolver -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
        <property name="prefix" value="/WEB-INF/jsp/"/>
        <property name="suffix" value=".jsp"/>
    </bean>
    

    InternalResourceViewResolver:支持JSP视图解析.

    viewClass:JstlView表示JSP模板页面需要使用JSTL标签库,所以classpath必须包含jstl的相关jar包;

    prefixsuffix:查找视图页面的前缀和后缀,最终视图的址为:前缀+逻辑视图名+后缀,逻辑视图名需要在controller中返回ModelAndView指定,比如逻辑视图名为hello,则最终返回的jsp视图地址“WEB-INF/jsp/hello.jsp”

    第八步:后端控制器开发

    后端控制器即controller,也有称为action

    importjavax.servlet.http.HttpServletRequest;
    importjavax.servlet.http.HttpServletResponse;
    importorg.springframework.web.servlet.ModelAndView;
    importorg.springframework.web.servlet.mvc.Controller;
    public class HelloWorldController implements Controller {
        @Override
        Public ModelAndView handleRequest(HttpServletRequest req, HttpServletResponse resp) throws Exception {
            ModelAndView mv = new ModelAndView();
            // 添加模型数据
            mv.addObject("message", "Hello World!");
            // 设置逻辑视图名,最终视图地址=前缀+逻辑视图名+后缀
            mv.setViewName("hello");
            return mv;
    

    org.springframework.web.servlet.mvc.Controller:处理器必须实现Controller 接口。

    ModelAndView:包含了模型数据及逻辑视图名

    第九步:后端控制器配置

    在springmvc-servlet.xml文件配置如下:

    <bean name="/hello.action" class="springmvc.action.HelloWorldController"/>
    

    name="/hello.action" :前边配置的BeanNameUrlHandlerMapping,表示如过请求的URL为“上下文/hello.action”,则将会交给该Bean进行处理。

    第十步:视图开发

    创建/WEB-INF/jsp/hello.jsp视图页面:

    <%@ page language="java" contentType="text/html; charset=UTF-8"
        pageEncoding="UTF-8"%>
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
            <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
            <title>第一个程序</title>
        </head>
            <!-- 显示一行信息hello world!!!! -->
            ${message}
        </body>
    </html>
    

    ${message}:表示显示由HelloWorldController处理器传过来的模型数据。

    第十一步:部署在tomcat测试

    通过请求:http://localhost:8080/springmvc_01/hello.action,如果页面输出“Hello World! ”就表明我们成功了。

    主要进行如下操作:

  • 前端控制器DispatcherServlet配置
    加载springmvc的配置文件
  • HandlerMapping配置
  • HandlerAdapter配置
  • ViewResolver配置
    前缀和后缀
  • 后端控制器编写
  • 后端控制器配置
  • 从上边的步骤可以看出,通常情况下我们只需要编写后端控制器和视图。

    6.HandlerMapping处理器映射器

    HandlerMapping 给前端控制器返回一个HandlerExecutionChain 对象(包含一个Handler (后端控制器)对象、多个HandlerInterceptor 拦截器)对象。

    BeanNameUrlHandlerMapping

    beanName Url映射器

    <!—beanName Url映射器 -->
    <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
    

    将后端控制器的bean name作为请求的url。

    SimpleUrlHandlerMapping

    <!—简单url映射 -->
        <bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
            <property name="mappings">
                <props>
                    <prop key="/hello1.action">hello_controller</prop>
                    <prop key="/hello2.action">hello_controller</prop>
                </props>
            </property>
        </bean>
    

    可定义多个url映射至一个后端控制器,hello_controller为后端控制器bean的id

    7.HandlerAdapter处理器适配器

    HandlerAdapter会把后端控制器包装为一个适配器,支持多种类型的控制器开发,这里使用了适配器设计模式。

    SimpleControllerHandlerAdapter

    简单控制器处理器适配器.

    所有实现了org.springframework.web.servlet.mvc.Controller接口的Bean作为Springmvc的后端控制器。

    适配器配置如下:

    <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter" />
    

    HttpRequestHandlerAdapter

    HTTP请求处理器适配器.

    HTTP请求处理器适配器将http请求封装成HttpServletResquestHttpServletResponse对象,和servlet接口类似。

    适配器配置如下:

    <bean class="org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter"/>
    

    Controller实现如下:

    publicclass HelloWorldController2 implements HttpRequestHandler {
        @Override
        publicvoid handleRequest(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException {
            request.setAttribute("message", "HelloWorld!");
            request.getRequestDispatcher("/WEB-INF/jsp/hello.jsp").forward(request, response);
                // 也可以自定义响应内容
                //response.setCharacterEncoding("utf-8");
                //response.getWriter().write("HelloWorld!");
    

    从上边可以看出此适配器器的controller方法没有返回ModelAndView,可通过response修改定义响应内容。

    8.Controller控制器

    AbstractCommandController(命令控制器)

    该控制器能把请求参数封装到一个命令对象(模型对象)中。

    public class MyCommandController extends AbstractCommandController {
         * 通过构造函数设置命令对象
        public MyCommandController(){
            this.setCommandClass(Student.class);
            this.setCommandName("student");//不是必须设置
        @Override
        protected ModelAndView handle(HttpServletRequest request,
                HttpServletResponse response, Object command, BindException errors)
                throws Exception {
            Student student = (Student)command;
            System.out.println(student);
            Return null;
         * 字符串转换为日期属性编辑器
        @Override
        Protected void initBinder(HttpServletRequest request,
                ServletRequestDataBinder binder) throws Exception {
            binder.registerCustomEditor(Date.class, new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"),true));
    
    publicclass Student {
        public Student() {
        public Student(String name) {
            this.name = name;
        private String name;//姓名
        private Integer age;//年龄
        private Date birthday;//生日
        private String address;//地址
    ….get/set方法省略
    

    Controller配置;

    <bean id="command_controller" name="/command.action" class="springmvc.action.MyCommandController"/>
    

    使用命令控制器完成查询列表及表单提交

    9.问题解决

    日期格式化

    在controller注册属性编辑器

    * 注册属性编辑器(字符串转换为日期) @InitBinder public void initBinder(HttpServletRequest request,ServletRequestDataBinder binder) throws Exception { binder.registerCustomEditor(Date.class, new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"),true));

    Post时中文乱码

    web.xml中加入:

    <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请求中文参数出现乱码解决方法有两个

    修改tomcat配置文件添加编码与工程编码一致,如下:

    <Connector URIEncoding="utf-8" connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443"/>
    

    另外一种方法对参数进行重新编码:

    String userName new String(request.getParamter("userName").getBytes("ISO8859-1"),"utf-8")
    

    ISO8859-1是tomcat默认编码,需要将tomcat编码后的内容按utf-8编码

    10.注解开发

    第一个例子

    创建工程的步骤同第一个springmvc工程,注解开发需要修改handlermapperhandlMapperAdapter,如下:

    springmvc-servlet.xml中配置:

    <!--注解映射器 -->   
        <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>
        <!--注解适配器 -->
        <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>
    

    注解映射器和注解适配器可以使用 <mvc:annotation-driven /> 代替。
    <mvc:annotation-driven /> 默认注册了注解映射器和注解适配器等bean。

    HelloWorldController编写:

    @Controller
    publicclass HelloWorldController {
        @RequestMapping(value="/hello")
        public String hello(Model model)throws Exception{
            model.addAttribute("message", "HelloWorld!");
            return"hello";
    

    注解描述

    @Controller:用于标识是处理器类

    @RequestMapping:请求到处理器功能方法的映射规则

    Controller配置

    在springmvc-servlet.xml中配置定义的controller:

    <!-- controller -->
    <bean class="springmvc.action.HelloWorldController"/>
    
    <context:component-scan base-package="springmvc.action" />
    

    扫描 @component@controller@service@repository 的注解

    注意:如果使用组件扫描则controller不需要在springmvc-servlet.xml中配置

    11.与struts2不同

  • springmvc的入口是一个servlet即前端控制器,而struts2入口是一个filter过虑器。
  • springmvc是基于方法开发,请求参数传递到方法的形参,可以设计为单例或多例(建议单例),struts2是基于类开发,传递参数是通过类的属性,只能设计为多例。
  • Struts采用值栈存储请求和响应的数据,通过OGNL存取数据, springmvc通过参数解析器是将request请求内容解析,并给方法形参赋值,将数据和视图封装成ModelAndView对象,最后又将ModelAndView中的模型数据通过reques域传输到页面。Jsp视图解析器默认使用jstl。
  • 不要在action类中定义方法所用到的变量,变量要定义到方法体中。因为方法是在栈内存中,不会导致线程问题。

    12.@Controller

    标识该类为控制器类,@controller@service@repository 分别对应了web应用三层架构的组件即控制器、服务接口、数据访问接口。

    13.@RequestMapping

    URL路径映射

    @RequestMapping(value="/user")或@RequestMapping("/user")

    根路径+子路径

    @RequestMapping 放在类名上边,如下:

    @Controller
    @RequestMapping("/user")
    

    @RequestMapping 放在方法名上边,如下:

    @RequestMapping("/useradd")
    public String useradd(….
    

    URI 模板模式映射

    @RequestMapping(value="/useredit/{userId}"):{×××}占位符,请求的URL可以是“/useredit/001”或“/useredit/abc”,通过在方法中使用@PathVariable 获取{×××}中的×××变量。

    @RequestMapping("/useredit/{userid}")
        public String useredit(@PathVariable String userid,Model model) throws Exception{
            //方法中使用@PathVariable获取useried的值,使用model传回页面
            model.addAttribute("userid", userid);
            return"/user/useredit";
    

    实现restFul,所有的url都是一个资源的链接,有利于搜索引擎对网址收录。

    多个占位符:

    @RequestMapping("/useredit/{groupid}/{userid}")
    public String useredit(@PathVariable String groupid,@PathVariable String userid,Model model) throws Exception{
            //方法中使用@PathVariable获取useried的值,使用model传回页面
            model.addAttribute("groupid", groupid);
            model.addAttribute("userid", userid);
            return"/user/useredit";
        <a href="${pageContext.request.contextPath}/user/editStudent/${student.id}/${student.groupId}/${student.sex}.action">修改</a>
    

    请求方法限定

    限定GET方法

    @RequestMapping(method = RequestMethod.GET)
    

    如果通过Post访问则报错:

    HTTP Status 405 - Request method 'POST' not supported

    @RequestMapping(value="/useredit/{userid}",method=RequestMethod.GET)
    

    限定POST方法

    @RequestMapping(method = RequestMethod.POST)
    

    如果通过Post访问则报错:

    HTTP Status 405 - Request method 'GET' not supported

    GET和POST都可以

    @RequestMapping(method={RequestMethod.GET,RequestMethod.POST})
    

    14.请求数据绑定(重点)

    Controller方法通过形参接收页面传递的参数。

    @RequestMapping("/userlist")
    public String userlist(
    HttpServletRequest request,
                HttpServletResponse response,
                HttpSession session,
                Model model
    

    默认支持的参数类型

    HttpServletRequest

    通过request对象获取请求信息

    HttpServletResponse

    通过response处理响应信息

    HttpSession

    通过session对象得到session中存放的对象

    session.setAttribute("userinfo", student);
    session.invalidate(); // 使session失效
    

    Model

    通过model向页面传递数据,如下:

    model.addAttribute("user", new User("李四"));
    

    页面通过${user.XXXX}获取user对象的属性值。

    命令/表单对象

    自动将请求参数绑定到功能处理方法的命令/表单对象上。

    Controller方法通过形参接收命令/表单对象。

    Java基本数据类型

    页面如下:

    <td>用户状态:</td> <inputtype="radio"name="userstate"value="true"/> <inputtype="radio"name="userstate"value="false"/>

    单精度/双精度

    日期型需要添加属性编辑器:

    @InitBinder
        Public void initBinder(HttpServletRequest request,ServletRequestDataBinder binder) throws Exception {
            binder.registerCustomEditor(Date.class, new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"),true));
    

    Pojo对象

    页面上以pojo对象中属性名称命名:

    将pojo对象中的属性名于传递进来的属性名对应,如果传进来的参数名称和对象中的属性名称一致则将参数值设置在pojo对象中

    页面定义如下;

    <input type="text" name="age"/>
    <input type="text" name="birthday"/>
    

    Contrller方法定义如下:

    public String useraddsubmit(Model model,User user)throws Exception{
        System.out.println(user);
    

    页面上以pojo对象名点属性名命名:

    如果采用类似struts中对象.属性的方式命名,需要将pojo对象作为一个包装对象的属性,action中以该包装对象作为形参。

    包装对象定义如下:

    Public class UserVo {
        private User user;
        public User getUser() {
            return user;
        Public void setUser(User user) {
            this.user = user;
    

    页面定义:

    <input type="text" name="user.age" />
    <input type="text" name="user.birthday" />
    

    Controller方法定义如下:

    public String useraddsubmit(Model model,UserVo userVo)throws Exception{
        System.out.println(userVo.getUser());
    

    字符串数组

    使用情景:页面提交批量数据以数组接受

    页面定义如下:

    页面选中多个checkbox向controller方法传递

    <c:forEach items="${studentList}" var="student">
            <td><input type="checkbox" name="deleteids" value="${student.id }"></td>
            <td>${student.id}</td>
            <td>${student.name}</td>
    

    传递到controller方法中的格式是:001,002,003

    Controller方法中可以用String[]接收,定义如下:

    @RequestMapping("/deleteStudent")
        public String deleteStudent(String[] deleteids)throws Exception {
            return "editStudentSubmit";
    

    List中存放对象,并将定义的List放在包装类中,action使用包装对象接收。

    List中对象:

    public class StudentScore {
        private String coursename;//课程名称
        private Float score;//成绩
        public String getCoursename() {
            returncoursename;
        Public void setCoursename(String coursename) {
            this.coursename = coursename;
        public Float getScore() {
            returnscore;
        Public void setScore(Float score) {
            this.score = score;
    Public class UserVo {
    Private List<StudentScore> scores;//成绩
      //get/set方法..
    

    包装类中定义List对象,并添加get/set方法如下:

    private List<StudentScore> scores;//成绩
        <td>课程成绩:</td>
            课程名:<input type="text"name="scores[0].coursename"/>成绩:<input type="text"name="scores[0].score"/><br/>
            课程名:<input type="text"name="scores[1].coursename"/>成绩:<input type="text"name="scores[1].score"/><br/>
            课程名:<input type="text"name="scores[2].coursename"/>成绩:<input type="text"name="scores[2].score"/><br/>
    

    Contrller方法定义如下:

    public String useraddsubmit(Model model,UserVo userVo)throws Exception{
    System.out.println(userVo.getScores ());
    

    在包装类中定义Map对象,并添加get/set方法,action使用包装对象接收。

    包装类中定义Map对象如下:

    Public class UserVo {
        private Map<String, Object>studentinfo = new HashMap<String, Object>();
      //get/set方法..
    

    页面定义如下:

    <td>学生信息:</td> 姓名:<inputtype="text"name="studentinfo['name']"/> 年龄:<inputtype="text"name="studentinfo['age']"/> .. .. .. <!-- studentinfo是包装对象中的属性名 []里边name是存储map中的key action中将map定义在包装对象中,以包装对象接收数据。--!>

    Contrller方法定义如下:

    public String useraddsubmit(Model model,UserVo userVo)throws Exception{
        System.out.println(userVo.getStudentinfo());
    

    注意:包含日期的要进行格式转换(放到action中

    // 使用注解进行日期格式数据转换
        @InitBinder
        private void initBinder(HttpServletRequest request, ServletRequestDataBinder binder) throws Exception {
            // 指定日期类型及日期数据的格式
            // 日期类型要和student类的birthday一致
            binder.registerCustomEditor(Date.class, new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"), true));
    

    @RequestParam绑定单个请求参数

    value:参数名字,即入参的请求参数名字,如value=“studentid”表示请求的参数区中的名字为studentid的参数的值将传入;

    required:是否必须,默认是true,表示请求中一定要有相应的参数,否则将报400错误码;
    defaultValue:默认值,表示如果请求中没有同名参数时的默认值

    定义如下:

    public String userlist(@RequestParam(defaultValue="2",value="group",required=true) String groupid) {
    

    形参名称为groupid,但是这里使用value="group"限定参数名为group,所以页面传递参数的名必须为group

    这里通过required=true限定groupid参数为必需传递,如果不传递则报400错误,由于使用了defaultvalue=”2”默认值即使不传group参数它的值为”2”,所以页面不传递group也不会报错,如果去掉defaultvalue=”2”且定义required=true则如果页面不传递group则会报错。

    @PathVariable 绑定URI 模板变量值

    @PathVariable用于将请求URL中的模板变量映射到功能处理方法的参数上

    @RequestMapping(value="/useredit/{groupid}/{userid}",method={RequestMethod.GET,RequestMethod.POST})
        public String useredit(@PathVariable String groupid,@PathVariable String userid,Model model) throws Exception{
            //方法中使用@PathVariable获取useried的值,使用model传回页面
            model.addAttribute("groupid", groupid);
            model.addAttribute("userid", userid);
            return"/user/useredit";
    

    如请求的URL 为“控制器URL/useredit/1/admin.action”,则自动将URL中模板变量{groupid}和{userid}绑定到@PathVariable注解的同名参数上,即入参后groupid=“1”userid=“admin”

    Redirect

    Contrller方法返回结果重定向到一个url地址,如果方式:

    return "redirect:/user/userlist.action";
    

    redirect方式相当于“response.sendRedirect()”,转发后浏览器的地址栏变为转发后的地址,因为转发即执行了一个新的requestresponse
    由于新发起一个request原来的参数在转发时就不能传递到下一个url,如果要传参数可以/user/userlist.action后边加参数,如下:

    /user/userlist.action?groupid=2&…..
    

    forward

    controller方法执行后继续执行另一个controller方法。

    return "forward:/user/userlist.action";
    

    forward 方式相当于“request.getRequestDispatcher().forward(request,response)”,转发后浏览器地址栏还是原来的地址。转发并没有执行新的request和response,而是和转发前的请求共用一个request和response。所以转发前请求的参数在转发后仍然可以读取到。

    如下例子:

    @RequestMapping("/c")
        public String c(String groupid,UserVo userVo)throws Exception{
            System.out.println("...c...."+groupid+"...user..."+userVo.getUser());
            return "forward:/to/d.action";
        @RequestMapping("/d")
        public String d(String groupid,UserVo userVo)throws Exception{
            System.out.println("...d...."+groupid+"...user..."+userVo.getUser());
            return "success";
    

    @RequestBody @ResponseBody实现json数据交互

    @RequestBody

    @RequestBody注解用于读取http请求的内容(字符串),通过springmvc提供的HttpMessageConverter接口将读到的内容转换为jsonxml等格式的数据并绑定到controller方法的参数上。

    本例子应用:

    @RequestBody注解实现接收http请求的json数据,将json数据转换为java对象.

    @ResponseBody

    该注解用于将Controller的方法返回的对象,通过HttpMessageConverter接口转换为指定格式的数据如:json,xml等,通过Response响应给客户端

    本例子应用:

    @ResponseBody注解实现将controller方法返回对象转换为json响应给客户端

    请求json,响应json实现:

    页面上请求的是一个json串,页面上实现时需要拼接一个json串提交到action。

    Action将请求的json串转为java对象。SpringMVC利用@ResquesBody注解实现.

    Action将java对象转为json,输出到页面。SpringMVC利用@ResponseBody注解实现.

    Springmvc默认用MappingJacksonHttpMessageConverterjson数据进行转换,需要加入jackson的包,如下:

    在注解适配器中加入messageConverters

    <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
        <property name="messageConverters">
                <bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"></bean>
            </list>
        </property>
    </bean>
    

    controller编写

    * 请求json单个对象,返回json单个对象 * @param user * @return * @throws Exception @RequestMapping("/requestjson") //@RequestBody接收json串自动转为user对象,@ResponseBody将user转为json数据响应给客户端 Public @ResponseBody User requestjson(@RequestBody User user)throws Exception{ System.out.println(user); return user;

    页面js方法编写:

    function request_json(){
             //将json对象传成字符串
        var user = JSON.stringify({name: "张三", age: 3});
        alert(user);
          $.ajax(
                type:'post',
                url:'${pageContext.request.contextPath}/requestjson.action',
                contentType:'application/json;charset=utf-8',//请求内容为json
                data:user,
                success: function(data){
                    alert(data.name);
    

    测试结果:

    从上图可以看出响应的数据也是json格式,json数据的内容是从User对象转换得来。

    Form提交,响应json实现

    采用form提交是最常用的作法,通常有post和get两种方法,响应json数据是为了方便客户端处理,实现如下:

    同第一个例子

    controller编写

    * 客户端提交表单,服务端返回json
    * @param user
    * @return
    * @throws Exception
    @RequestMapping("/formsubmit")
    Public @ResponseBody User formsubmit(User user)throws Exception{
    System.out.println(user);
    return user;

    页面js方法编写:

    function formsubmit(){
        var user = "name=张三&age=3";
        alert(user);
          $.ajax(
                type:'post',//这里改为get也可以正常执行
                url:'${pageContext.request.contextPath}/formsubmit.action',
                //ContentType没指定将默认为:application/x-www-form-urlencoded
                data:user,
                success:function(data){
                alert(data.name);
    

    从上边的js代码看出,已去掉ContentType的定义,ContentType默认为:application/x-www-form-urlencoded格式。

    测试结果:

    从上图可以看出响应的数据也是json格式,json数据的内容是从User对象转换得来。

    <mvc:annotation-driven />配置:

    注解映射器和注解适配器可以使用 <mvc:annotation-driven /> 代替。

    <mvc:annotation-driven /> 默认注册了注解映射器和注解适配器等bean。

    以下配置可用 <mvc:annotation-driven /> 代替:

    <!--注解映射器 -->   
        <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>
        <!--注解适配器 -->
        <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
            <property name="messageConverters">
            <bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"></bean>
            </list>
            </property>
        </bean>
    

    15.拦截器

    Spring Web MVC 的处理器拦截器类似于Servlet 开发中的过滤器Filter,用于对处理器进行预处理和后处理。
    SpringMVC拦截器是针对mapping配置的拦截器

    拦截器定义

    实现HandlerInterceptor接口,如下:

    Public class HandlerInterceptor1 implements HandlerInterceptor{
         * controller执行前调用此方法
         * 返回true表示继续执行,返回false中止执行
         * 这里可以加入登录校验、权限拦截等
        @Override
        Public boolean preHandle(HttpServletRequest request,
                HttpServletResponse response, Object handler) throws Exception {
            Return false;
         * controller执行后但未返回视图前调用此方法
         * 这里可在返回用户前对模型数据进行加工处理,比如这里加入公用信息以便页面显示
        @Override
        Public void postHandle(HttpServletRequest request,
                HttpServletResponse response, Object handler,
                ModelAndView modelAndView) throws Exception {
         * controller执行后且视图返回后调用此方法
         * 这里可得到执行controller时的异常信息
         * 这里可记录操作日志,资源清理等
        @Override
        Public void afterCompletion(HttpServletRequest request,
                HttpServletResponse response, Object handler, Exception ex)
                throws Exception {      
    

    拦截器配置

    针对某种mapping配置拦截器

    class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"> <property name="interceptors"> <ref bean="handlerInterceptor1"/> <ref bean="handlerInterceptor2"/> </list> </property> </bean> <bean id="handlerInterceptor1" class="springmvc.intercapter.HandlerInterceptor1"/> <bean id="handlerInterceptor2" class="springmvc.intercapter.HandlerInterceptor2"/>

    针对所有mapping配置全局拦截器

    <!--拦截器 -->
    <mvc:interceptors>
        <!--多个拦截器,顺序执行 -->
        <mvc:interceptor>
            <mvc:mapping path="/**"/>
            <bean class="cn.itcast.springmvc.filter.HandlerInterceptor1"></bean>
        </mvc:interceptor>
        <mvc:interceptor>
            <mvc:mapping path="/**"/>
            <bean class="cn.itcast.springmvc.filter.HandlerInterceptor2"></bean>
        </mvc:interceptor>
    </mvc:interceptors>
    

    正常流程测试

    HandlerInterceptor1..preHandle..

    HandlerInterceptor2..preHandle..

    HandlerInterceptor2..postHandle..

    HandlerInterceptor1..postHandle..

    HandlerInterceptor2..afterCompletion..

    HandlerInterceptor1..afterCompletion..

    中断流程测试

    定义两个拦截器分别为:HandlerInterceptor1HandlerInteptor2

    HandlerInterceptor1preHandler方法返回false,HandlerInterceptor2返回true,运行流程如下:

    HandlerInterceptor1..preHandle..

    从日志看出第一个拦截器的preHandler方法返回false后第一个拦截器只执行了preHandler方法,其它两个方法没有执行,第二个拦截器的所有方法不执行,且controller也不执行了。

    HandlerInterceptor1preHandler方法返回trueHandlerInterceptor2返回false,运行流程如下:

    HandlerInterceptor1..preHandle..

    HandlerInterceptor2..preHandle..

    HandlerInterceptor1..afterCompletion..

    从日志看出第二个拦截器的preHandler方法返回false后第一个拦截器的ostHandler没有执行,第二个拦截器的postHandlerafterCompletion没有执行,且controller也不执行了。

    preHandle按拦截器定义顺序调用

    postHandler按拦截器定义逆序调用

    afterCompletion按拦截器定义逆序调用

    postHandler在拦截器链内所有拦截器返成功调用
    afterCompletion只有preHandle返回true才调用

    拦截器应用

    用户身份认证

    Public class LoginInterceptor implements HandlerInterceptor{
        @Override
        Public boolean preHandle(HttpServletRequest request,
                HttpServletResponse response, Object handler) throws Exception {
            //如果是登录页面则放行
            if(request.getRequestURI().indexOf("login.action")>=0){
                return true;
            HttpSession session = request.getSession();
            //如果用户已登录也放行
            if(session.getAttribute("user")!=null){
                return true;
            //用户没有登录挑战到登录页面
            request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request, response);