• SpringMVC详解


    高级参数绑定

    绑定数组

        jsp中获取list集合并遍历

    <c:forEach items="${itemList }" var="item">
    <tr>
        <td><input name="ids" value="${item.id}" type="checkbox"></td>
        <td>${item.name }</td>
        <td>${item.price }</td>
        <td><fmt:formatDate value="${item.createtime}" pattern="yyyy-MM-dd HH:mm:ss"/></td>
        <td>${item.detail }</td>
        <td><a href="${pageContext.request.contextPath }/itemEdit.action?id=${item.id}">修改</a></td>
    </tr>
    </c:forEach>

      

        controller层接收参数并操作

    1 @RequestMapping("/itemEdit")
    2     public void itemEdit(QueryVo queryVo, String[] ids) {
    3             queryVo.getItems.setName( (queryVo.getItems().getName());
    4         queryVo.getItems.setPrice( (queryVo.getItems().getPrice());
    5         ...
    6     }

    @RequestMapping

    通过RequestMapping注解可以定义不同的处理器映射规则。

    窄化请求映射

    @RequestMapping("/item")放在类名上边,设置请求前缀

    @RequestMapping("/queryItem ")放在方法名上边,请求url为 /前缀/queryItem

    请求方法限定

         默认请求方式为get请求    

    •   限定GET方法

    @RequestMapping(method = RequestMethod.GET)

    如果通过Post访问则报错:HTTP Status 405 - Request method 'POST' not supported

    例如:

    @RequestMapping(value="/editItem",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})


    controller层方法返回值

    • 返回ModelAndView

        controller方法中定义ModelAndView对象并返回,对象中可添加model数据、指定view页面。

    • 返回void

    在controller方法形参上可以定义request和response,使用request或response指定响应结果:

    1、使用request转向页面,如下:

    request.getRequestDispatcher("页面路径").forward(request, response);

    2、也可以通过response页面重定向:

    response.sendRedirect("url")

    3、也可以通过response指定响应结果,例如响应json数据如下:

    response.setCharacterEncoding("utf-8");

    response.setContentType("application/json;charset=utf-8");

    response.getWriter().write("json串");

    • 返回字符串

        逻辑视图名 

          controller方法返回字符串可以指定逻辑视图名,通过视图解析器解析为物理视图地址。

    //指定逻辑视图名,经过视图解析器解析为jsp物理路径:/WEB-INF/jsp/item/editItem.jsp
    return "item/editItem";

        Redirect重定向

          Contrller方法返回结果重定向到一个url地址,如下商品修改提交后重定向到商品查询方法,参数无法带到商品查询方法中。

    //重定向到queryItem.action地址,request无法带过去
    return "redirect:queryItem.action";

    redirect方式相当于“response.sendRedirect()”,转发后浏览器的地址栏变为转发后的地址,因为转发即执行了一个新的request和response。

    由于新发起一个request原来的参数在转发时就不能传递到下一个url,如果要传参数可以/item/queryItem.action后边加参数,如下:

    /item/queryItem?...&…..

        forward转发

          controller方法执行后继续执行另一个controller方法,如下商品修改提交后转向到商品修改页面,修改商品的id参数可以带到商品修改方法中。

    //结果转发到editItem.action,request可以带过去
    return "forward:editItem.action";

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

    请求重定向与请求转发的区别:

    请求转发forward:浏览器URL地址不会发生变化,在服务器端做了一个跳转,同一个request域中

    请求重定向redirect:浏览器地址会发生变化,服务器端向浏览器响应302状态码,浏览器收到302之后,重新请求服务器一个新的地址,不同的request域了


    异常处理器

      异常处理思路

        系统中异常包括两类:预期异常运行时异常RuntimeException,前者通过捕获异常从而获取异常信息,后者主要通过规范代码开发、测试通过手段减少运行时异常的发生。

             系统的dao、service、controller出现都通过throws Exception向上抛出,最后由springmvc前端控制器交由异常处理器进行异常处理,如下图:

    •   自定义异常类

        为了区别不同的异常通常根据异常类型自定义异常类,有时需要创建一个自定义系统异常,如果controller、service、dao抛出此类异常说明是系统预期处理的异常信息。

     1 public class CustomException extends Exception {
     2     /** serialVersionUID*/
     3     private static final long serialVersionUID = -5212079010855161498L;
     4     
     5     public CustomException(String message){
     6         super(message);
     7         this.message = message;
     8     }
     9 
    10     //异常信息
    11     private String message;
    12 
    13     public String getMessage() {
    14         return message;
    15     }
    16 
    17     public void setMessage(String message) {
    18         this.message = message;
    19     }
    20 }
    •   自定义异常处理器实现HandlerExceptionResolver

     1 public class CustomExceptionResolver implements HandlerExceptionResolver {
     2     @Override
     3     public ModelAndView resolveException(HttpServletRequest request,
     4             HttpServletResponse response, Object handler, Exception ex) {
     5         String msg = null;
     6         if(ex instanceof CustomerException){
     7             CustomerException exception = (CustomerException) ex;
     8             msg = exception.getMessage();
     9         }else{
    10             StringWriter s = new StringWriter();
    11             PrintWriter printWriter = new PrintWriter(s);
    12             ex.printStackTrace(printWriter);
    13             msg = s.toString();
    14         }
    15         ModelAndView view = new ModelAndView();
    16         view.setViewName("error");
    17         view.addObject("message", msg);
    18         return modelAndView;
    19     }
    20 }
    •   错误页面

    <%@ page language="java" contentType="text/html; charset=UTF-8"
        pageEncoding="UTF-8"%>
    <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
    <%@ taglib uri="http://java.sun.com/jsp/jstl/fmt"  prefix="fmt"%> 
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>错误页面</title>
    </head>
    <body>
    您的操作出现错误如下:<br/>
    ${message}
    </body>
    </html>
    •   异常处理器配置

        在springmvc.xml中添加:

       <!-- 异常处理器 -->
        <bean id="handlerExceptionResolver" class="cn.itcast.ssm.controller.exceptionResolver.CustomExceptionResolver"/>
    •   异常测试

        需求:修改商品信息,id输入错误提示商品信息不存在。

        实现:修改controller方法“editItem”,调用service查询商品信息,如果商品信息为空则抛出异常:

    1        // 调用service查询商品信息
    2         Items item = itemService.findItemById(id);
    3         if(item == null){
    4             throw new CustomException("商品信息不存在!");
    5         }

    上传图片

      配置tomcat代理目录

    在tomcat上配置图片虚拟目录,在tomcat下conf/server.xml中添加:

    <Context docBase="F:developupload emp" path="/pic" reloadable="false"/>

    访问http://localhost:8080/pic即可访问F:developupload emp下的图片。

      也可以通过eclipse配置:

    •   依赖的jar包

    <!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
    <dependency>
        <groupId>commons-io</groupId>
        <artifactId>commons-io</artifactId>
        <version>2.4</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
    <dependency>
        <groupId>commons-fileupload</groupId>
        <artifactId>commons-fileupload</artifactId>
        <version>1.3.1</version>
    </dependency>
    •   配置解析器

        <!-- 文件上传 -->
        <bean id="multipartResolver"
            class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
            <!-- 设置上传文件的最大尺寸为5MB -->
            <property name="maxUploadSize" value="5242880"></property>    
       </bean>
        
    •   图片上传

        

        controller:

     1    //商品修改提交
     2     @RequestMapping("/imgSubmit")
     3     public String imgSubmit(MultipartFile pictureFile)throws Exception{        
     4         //原始文件名称
     5         String pictureFile_name =  pictureFile.getOriginalFilename();
     6         //新文件名称
     7         String newFileName = UUID.randomUUID().toString()+pictureFile_name.substring(pictureFile_name.lastIndexOf("."));
     8         
     9         //上传图片
    10         File uploadPic = new java.io.File("F:/develop/upload/temp/"+newFileName);
    11         
    12         if(!uploadPic.exists()){
    13             uploadPic.mkdirs();
    14         }
    15         //向磁盘写文件
    16         pictureFile.transferTo(uploadPic);
    17 
    18 .....

        页面:

    <!-- form添加enctype="multipart/form-data":-->
    <form id="imgForm"
    action="${pageContext.request.contextPath }/imgSubmit.action"
            method="post" enctype="multipart/form-data">
            <input type="hidden" name="pic" value="${item.pic }" />
    
    
    <!-- file的name与controller形参一致:-->
    <tr>
        <td>商品图片</td>
        <td><c:if test="${item.pic !=null}">
                <img src="/pic/${item.pic}" width=100 height=100 />
                <br />
            </c:if> <input type="file" name="pictureFile" /></td>
    </tr>

    json数据交互

      @RequestBody

    作用:

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

    List.action?id=1&name=zhangsan&age=12

      @ResponseBody

    作用:

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

      请求json,响应json实现

        1、依赖jar包

    <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core -->
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-core</artifactId>
        <version>2.8.8</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.8.8</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations -->
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-annotations</artifactId>
        <version>2.8.8</version>
    </dependency>

      

       2、配置json转换器

      在注解适配器中加入messageConverters

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

      注意:如果使用<mvc:annotation-driven /> 则不用定义上边的内容。

       3、controller层

    1    // 商品修改提交json信息,响应json信息
    2     @RequestMapping("/editItemSubmit_RequestJson")
    3    @ResponseBody
    4     public Items editItemSubmit_RequestJson(@RequestBody Items items) throws Exception {
    5         System.out.println(items);
    6         return items;
    7     }

       4、页面js方法

    //引入 js:
    <script type="text/javascript" 
    src="${pageContext.request.contextPath }/js/jquery-1.4.4.min.js"></script>
    
    
        //请求json响应json
        function request_json(){
            $.ajax({
                type:"post",
                url:"${pageContext.request.contextPath }/item/editItemSubmit_RequestJson.action",
                contentType:"application/json;charset=utf-8",
                data:'{"name":"测试商品","price":99.9}',
                success:function(data){
                    alert(data);
                }
            });
        }

    RESTful支持

    Restful就是一个资源定位及资源操作的风格。不是标准也不是协议,只是一种风格,是对http协议的诠释

    资源定位:互联网所有的事物都是资源,要求url中没有动词,只有名词。没有参数

    Url格式:http://blog.csdn.net/briblue/article/details/73824058

    资源操作:使用put、delete、postget,使用不同方法对资源进行操作。分别对应添加、删除、修改、查询。一般使用时还是post和get。Put和Delete几乎不使用。

    •   添加DispatcherServlet的rest配置

    <servlet>
            <servlet-name>springmvc-servlet-rest</servlet-name>
            <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
            <init-param>
                <param-name>contextConfigLocation</param-name>
                <param-value>classpath:spring/springmvc.xml</param-value>
            </init-param>
        </servlet>
        <servlet-mapping>
            <servlet-name>springmvc-servlet-rest</servlet-name>
    
            <!-- / :表示拦截所有请求,但是不拦截jsp
                /*  : 表示所有的请求都会拦截,包括jsp
                一般都是推荐只使用  /
             -->
            <url-pattern>/</url-pattern>    
    </servlet-mapping>
    •   URL 模板模式映射

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

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

     

        @RequestMapping("/itemEdit/{id}")//id和形参名称一致
        public String getItemEdit(Model model,@PathVariable("id")Integer id) throws CustomerException{//@PathVariable不用指定名称。
            Items  items = itemService.getItemById(id);
            //view.addObject("item", items);
            model.addAttribute("item", items);
            return "editItem";
        }
    •   静态资源访问<mvc:resources>

    如果在DispatcherServlet中设置url-pattern为 /则必须对静态资源进行访问处理。

    spring mvc 的<mvc:resources mapping="" location="">实现对静态资源进行映射访问。

      如下是对js文件访问配置:

      <mvc:resources location="/js/" mapping="/js/**"/>


    拦截器

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

    区别: 拦截器不需要依赖servlet容器,过滤器需要依赖于javaWeb的环境

        拦截器是spring提供的一种机制,过滤器是javaWeb提供的一种支持

       一、定义拦截器

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

       二、配置拦截器

          1、针对某种mapping配置拦截器

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

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

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

       三、正常流程测试

      定义两个拦截器分别为:HandlerInterceptor1和HandlerInteptor2,每个拦截器的preHandler方法都返回true。

      运行结果:

    HandlerInterceptor1..preHandle..

    HandlerInterceptor2..preHandle..

     

    HandlerInterceptor2..postHandle..

    HandlerInterceptor1..postHandle..

    HandlerInterceptor2..afterCompletion..

    HandlerInterceptor1..afterCompletion..

     

       四、中断流程测试

      

      HandlerInterceptor1的preHandler方法返回false,HandlerInterceptor2返回true,运行流程如下:

        HandlerInterceptor1..preHandle..

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

      HandlerInterceptor1的preHandler方法返回true,HandlerInterceptor2返回false,运行流程如下:

        HandlerInterceptor1..preHandle..

        HandlerInterceptor2..preHandle..

        HandlerInterceptor1..afterCompletion..

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

      总结

    preHandle按拦截器定义顺序调用

    postHandler按拦截器定义逆序调用

    afterCompletion按拦截器定义逆序调用

    postHandler在拦截器链内所有拦截器返成功调用

    afterCompletion只有preHandle返回true才调用

       * 拦截器应用

    1、有一个登录页面,需要写一个controller访问页面

    2、登录页面有一提交表单的动作。需要在controller中处理。

    a)       判断用户名密码是否正确

    b)       如果正确 向session中写入用户信息

    c)        返回登录成功,或者跳转到商品列表

    3、拦截器。

    a)       拦截用户请求,判断用户是否登录

    b)       如果用户已经登录。放行

    c)        如果用户未登录,跳转到登录页面。

      用户身份认证

    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);
            
            return false;
        }
    }

      

      controller

       //登陆页面
        @RequestMapping("/login")
        public String login(Model model)throws Exception{        
            return "login";
        }
        
        //登陆提交
        //userid:用户账号,pwd:密码
        @RequestMapping("/loginsubmit")
        public String loginsubmit(HttpSession session,String userid,String pwd)throws Exception{        
            //向session记录用户身份信息
            session.setAttribute("activeUser", userid);
            
            return "redirect:item/queryItem.action";
        }
        
        //退出
        @RequestMapping("/logout")
        public String logout(HttpSession session)throws Exception{    
            //session过期
            session.invalidate();      
            return "redirect:item/queryItem.action";
        }
  • 相关阅读:
    微信开发者工具
    (转)一个基于vue2的天气js应用
    (转)Vue2.0 推荐环境
    编写高质量代码:改善Java程序的151个建议(第3章:类、对象及方法___建议36~40)
    编写高质量代码:改善Java程序的151个建议(第3章:类、对象及方法___建议31~35)
    编写高质量代码:改善Java程序的151个建议(第2章:基本类型___建议26~30)
    编写高质量代码:改善Java程序的151个建议(第2章:基本类型___建议21~25)
    编写高质量代码:改善Java程序的151个建议(第1章:JAVA开发中通用的方法和准则___建议16~20)
    编写高质量代码:改善Java程序的151个建议(第1章:JAVA开发中通用的方法和准则___建议11~15)
    编写高质量代码:改善Java程序的151个建议(第1章:JAVA开发中通用的方法和准则___建议6~10)
  • 原文地址:https://www.cnblogs.com/jifengblog/p/9248510.html
Copyright © 2020-2023  润新知