• Java web开发(17)SpirngMVC 详解


    注解类和方法大致如下

    @Controller
    @RequestMapping("/URL跟路径")
    public class CLassXXXController{
    
    @RequestMapping("/URL子路径1")
    public ModelAndView Method_1(参数1,参数2,...参数n)
    
    ......
    
    ModelAndView modelAndView = new ModelAndView();
    // 相当 于request的setAttribut,在jsp页面中通过itemsList取数据
    modelAndView.addObject("itemsList", itemsList);
    modelAndView.setViewName("items/itemsList");
    return modelAndView;
    }
    
    @RequestMapping("/URL子路径1")
    public String Method_2(参数1,参数2,...参数n)
    
    ......
    
    //等效上面的
    return "items/itemsList";
    }

    返回值说明

    方法1:

    上面两种返回都是转发,如果定义了视图解析器

        <bean
            class="org.springframework.web.servlet.view.InternalResourceViewResolver">
            <!-- 配置jsp路径的前缀 -->
            <property name="prefix" value="/WEB-INF/jsp/" />
            <!-- 配置jsp路径的后缀 -->
            <property name="suffix" value=".jsp" />
        </bean>

    那么转发的路径就是"/WEB-INF/jsp/items/itemsList.jsp",全路径也就是host/项目名//WEB-INF/jsp/items/itemsList.jsp

    方法2:

    返回"redirect:XXX", 或者"forward:XXX",重定向request不共享,转发request共享。

    注意:此时路径是相对于类名上的根路径。比如类上的RequestMapping("hello"),那么会转发到host/项目名/hello/XXX

    参数绑定

    方法中可以有任意数量的参数,可以是HttpServletResponse,HttpServletRequest,HttpSession,ModelMap,

    基本类型,自定义的类。

    简单类型

    @RequestMapping("/hei")

    public String Fun1(Integer id,其他参数)

    访问该路径时有一个key名称为id,value会自动绑定。

    名称不一致的绑定

    public String Fun1(@RequestParam(value="id",required=true) Integer xxxd,其他参数)

    POJO绑定

    public class OneThing{
    private Integer id;
    private String name;
    private String place;
    private Date createDate;
    private String comment;
    }
    @RequestMapping("/onething")
    public String Fun2(OneThing thing,其他参数){
    ....
    }

    访问该路径时,当key/value中key的名称和POJO类属性名称一致,其值会绑定到该pojo对象中。

    特殊情况:日期类型。访问页面提供的日期字符需要转换,才能绑定到pojo的Date对象。

    创建转换类

    public class CustomDateConverter implements Converter<String,Date>{
    
        public Date convert(String source) {
            
            //实现 将日期串转成日期类型(格式是yyyy-MM-dd HH:mm:ss)
            
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            
            try {
                //转成直接返回
                return simpleDateFormat.parse(source);
            } catch (ParseException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            //如果参数绑定失败返回null
            return null;
        }
    
    }

    在springmvc.xml中配置

    <!-- 自定义参数绑定 -->
        <bean id="conversionService"
            class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
            <!-- 转换器 -->
            <property name="converters">
                <list>
                    <!-- 日期类型转换 -->
                    <bean
                        class="com.legion.ssm.controller.converter.CustomDateConverter" />
                </list>
            </property>
        </bean>
    
        <mvc:annotation-driven
            conversion-service="conversionService"></mvc:annotation-driven>

     包装类型pojo绑定

    上面的OneThing类添加一个新的属性,

     private Item myitem;

    这个属性也是一个pojo类,当访问提供的key/value的时候key名称为

    myitem.name等等的形式时,其会绑定到OneThing对象中。

    数组类型

    出现场景:前端使用复选框

    用户提交多个记录,此时items_id会有多个记录,

    @RequestMapping("/deleteItems")
        public String deleteItems(int[] items_id) throws Exception {

     List绑定

    前端形如

    <c:forEach items="${itemsList }" var="item" varStatus="status">
    <tr>    
    
        <td><input name="itemsList[${status.index }].name" value="${item.name }"/></td>
        <td><input name="itemsList[${status.index }].price" value="${item.price }"/></td>
        <td><input name="itemsList[${status.index }].createtime" value="<fmt:formatDate value="${item.createtime}" pattern="yyyy-MM-dd HH:mm:ss"/>"/></td>
        <td><input name="itemsList[${status.index }].detail" value="${item.detail }"/></td>
    
    
    </tr>
    </c:forEach>

    http协议数据就是

    itemLists[0].name=XXX&itemLists[0].price=XXX&itemLists[0].detail=XX......itemLists[1].name=XXX&itemLists[1].price=XXX.....

    @RequestMapping("/onething")
    public String Fun2(OneThing thing,其他参数){
    ....
    }
    //OneThing类新增一个List类型的属性
    private List<Item> itemsList;

    http协议 中的数据会绑定到OneThing对象中去

    SpringMVC校验

     maven配置,使用了tomcat8

            <dependency>
                <groupId>org.glassfish</groupId>
                <artifactId>javax.el</artifactId>
                <version>3.0.1-b08</version>
            </dependency>
            <dependency>
                <groupId>org.hibernate.validator</groupId>
                <artifactId>hibernate-validator</artifactId>
                <version>6.0.7.Final</version>
            </dependency>

    在springmvc.xml中配置

        <!-- 校验器 -->
        <bean id="validator"
            class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
            <!-- hibernate校验器 -->
            <property name="providerClass"
                value="org.hibernate.validator.HibernateValidator" />
            <!-- 指定校验使用的资源文件,在文件中配置校验错误信息,如果不指定则默认使用classpath下的ValidationMessages.properties -->
            <property name="validationMessageSource" ref="messageSource" />
        </bean>
        <!-- 校验错误信息配置文件 -->
        <bean id="messageSource"
            class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
            <!-- 资源文件名 -->
            <property name="basenames">
                <list>
                    <value>classpath:CustomValidationMessages</value>
                </list>
            </property>
            <!-- 资源文件编码格式 -->
            <property name="fileEncodings" value="utf-8" />
            <!-- 对资源文件内容缓存时间,单位秒 -->
            <property name="cacheSeconds" value="120" />
        </bean>
    
        <mvc:annotation-driven
            conversion-service="conversionService" validator="validator"></mvc:annotation-driven>

    在Pojo类,比如ItemsCustom的属性上添加注解

    @Size(min=3,max=30,message="{items.name.length.error}")
    private String name;
    //已经建立CustomValidationMessages.properties文件
    //指定了字符串items.name.length.error的值

    关键使用:需要验证的pojo类前面加@Validated,后面跟BindingResult对象,用于错误处理

            @RequestMapping("/editItemsSubmit")
        public String editItemsSubmit( @Validated ItemsCustom itemsCustom,BindingResult br)
    {。。。
    } 

    错误处理

    if(br.hasErrors()) {
                List<ObjectError> ae=br.getAllErrors();
                for(ObjectError oe:ae) {
                    System.out.println(oe.getDefaultMessage());
                }

    分组校验

    先建立一个接口VG1,

    在pojo类需要验证的属性上这样使用

        @Size(min=5,max=30,message="{items.name.length.error}",groups= {VG1.class})
        private String name;

    验证的时候

    @RequestMapping("/editItemsSubmit")
     public String editItemsSubmit( @Validated(value={VG1.class}) ItemsCustom itemsCustom,BindingResult br)
    {。。。
    } 

     数据回显

    把对象放到request域中

    方法1:

    在参数中添加Model 对象m

    m.addAttribute("id",对象名);

    上传图片

    配置springmvc.xml

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

    pom中添加commons-fileupload

    创建虚拟目录存储图片

    或者修改tomcat的配置

    在conf/server.xml文件中添加

    上传页面的前端代码注意事项:

    Form中添加

    enctype="multipart/form-data"

            <input type="file"  name="items_pic"/> 

    对应处理handler参数中必须有

    MultipartFile items_pic

    对象名必须和前端的上传name一样

    相关处理代码

    String originalFilename = items_pic.getOriginalFilename();
    //上传图片
    if(items_pic!=null && originalFilename!=null && originalFilename.length()>0){
        //存储图片的物理路径
        String pic_path = "D:\我的文档\Pictures\";
        //新的图片名称
        String newFileName = UUID.randomUUID() + originalFilename.substring(originalFilename.lastIndexOf("."));
        File newFile = new File(pic_path+newFileName);
        //将内存中的数据写入磁盘
        items_pic.transferTo(newFile);
        //将新图片名称写到itemsCustom中
        itemsCustom.setPic(newFileName);
    }

     JSON处理

    pom.xml配置

            <dependency>
                <groupId>com.fasterxml.jackson.core</groupId>
                <artifactId>jackson-core</artifactId>
                <version>2.9.6</version>
            </dependency>
            <dependency>
                <groupId>com.fasterxml.jackson.core</groupId>
                <artifactId>jackson-databind</artifactId>
                <version>2.9.6</version>
            </dependency>

    使用Jquery的配置

    静态资源配置,在springmvc.xml中配置

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

    项目中添加js文件

    前端代码

    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>json交互测试</title>
    <script type="text/javascript" src="${pageContext.request.contextPath }/js/jquery-1.4.4.min.js"></script>
    <script type="text/javascript">
    //请求json,输出是json
    function requestJson(){
        
        $.ajax({
            type:'post',
            url:'${pageContext.request.contextPath }/requestJson',
            contentType:'application/json;charset=utf-8',
            //数据格式是json串,商品信息
            data:'{"name":"手机","price":999}',
            success:function(data){//返回json结果
                alert(JSON.stringify(data));
            }
            
        });
        
        
    }
    //请求key/value,输出是json
    function responseJson(){
        
        $.ajax({
            type:'post',
            url:'${pageContext.request.contextPath }/responseJson',
            //请求是key/value这里不需要指定contentType,因为默认就 是key/value类型
            //contentType:'application/json;charset=utf-8',
            //数据格式是json串,商品信息
            data:'name=手机&price=999',
            success:function(data){//返回json结果
                alert(JSON.stringify(data));
            }
            
        });
        
    }
    </script>
    </head>
    <body>
    <input type="button" onclick="requestJson()" value="请求json,输出是json"/>
    <input type="button" onclick="responseJson()" value="请求key/value,输出是json"/>
    </body>
    </html>

    后端处理代码

    @Controller
    public class JsonTest {
        
    
        @RequestMapping("/requestJson")
        public @ResponseBody ItemsCustom requestJson(@RequestBody ItemsCustom ic ) {
            ic.setPic("The legion has returned...");
            return ic;
        }
        
        @RequestMapping("/responseJson")
        public @ResponseBody ItemsCustom responseJson(ItemsCustom itemsCustom){
            
            //@ResponseBody将itemsCustom转成json输出
            return itemsCustom;
        }
    }

     拦截器

     类的定义,需要实现HandlerInterceptor接口

    public class HandlerInterceptor1 implements HandlerInterceptor {
    
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
                throws Exception {
            // TODO Auto-generated method stub
            System.out.println("拦截器11 之前");
            return true;
        }
    
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
                ModelAndView modelAndView) throws Exception {
            // TODO Auto-generated method stub
            System.out.println("拦截器11 之后");
        }
    
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
                throws Exception {
            // TODO Auto-generated method stub
            System.out.println("拦截器11完成");
        }
    
    }

    在springmvc.xml中配置

        <!--拦截器 -->
        <mvc:interceptors>
            <!--多个拦截器,顺序执行 -->
        <mvc:interceptor>
        <!-- /**表示所有url包括子url路径 -->
        <mvc:mapping path="/**" />
        <bean class="com.legion.ssm.interceptor.HandlerInterceptor1"></bean>
        </mvc:interceptor>
    
        <mvc:interceptor>
        <mvc:mapping path="/**" />
        <bean class="com.legion.ssm.interceptor.HandlerInterceptor2"></bean>
        </mvc:interceptor>
        </mvc:interceptors>

    测试总结

    两个拦截器都放行
    
    HandlerInterceptor1...preHandle
    HandlerInterceptor2...preHandle
    
    HandlerInterceptor2...postHandle
    HandlerInterceptor1...postHandle
    
    HandlerInterceptor2...afterCompletion
    HandlerInterceptor1...afterCompletion
    
    总结:
    preHandle方法按顺序执行,
    postHandle和afterCompletion按拦截器配置的逆向顺序执行。
    
    拦截器1放行,拦截器2不放行
    HandlerInterceptor1...preHandle
    HandlerInterceptor2...preHandle
    HandlerInterceptor1...afterCompletion
    
    总结:
    拦截器1放行,拦截器2 preHandle才会执行。
    拦截器2 preHandle不放行,拦截器2 postHandle和afterCompletion不会执行。
    只要有一个拦截器不放行,postHandle不会执行。
    
    拦截器1不放行,拦截器2不放行
    HandlerInterceptor1...preHandle
    
    拦截器1 preHandle不放行,postHandle和afterCompletion不会执行。
    拦截器1 preHandle不放行,拦截器2不执行。

    使用拦截器实现登录认证

        如果请求的url是公开地址(无需登陆即可访问的url),让放行
        如果用户session 不存在跳转到登陆页面
        如果用户session存在放行,继续操作。
    public class LoginInterceptor implements HandlerInterceptor {
    
        
        //进入 Handler方法之前执行
        //用于身份认证、身份授权
        //比如身份认证,如果认证通过表示当前用户没有登陆,需要此方法拦截不再向下执行
        public boolean preHandle(HttpServletRequest request,
                HttpServletResponse response, Object handler) throws Exception {
            
            //获取请求的url
            String url = request.getRequestURI();
            //判断url是否是公开 地址(实际使用时将公开 地址配置配置文件中)
            //这里公开地址是登陆提交的地址
            if(url.indexOf("login")>=0){
                //如果进行登陆提交,放行
                return true;
            }
            
            //判断session
            HttpSession session  = request.getSession();
            //从session中取出用户身份信息
            String username = (String) session.getAttribute("username");
            
            if(username != null){
                //身份存在,放行
                return true;
            }
            
            //执行这里表示用户身份需要认证,跳转登陆页面
            request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request, response);
            
            //return false表示拦截,不向下执行
            //return true表示放行
            return false;
        }
    
        //进入Handler方法之后,返回modelAndView之前执行
        //应用场景从modelAndView出发:将公用的模型数据(比如菜单导航)在这里传到视图,也可以在这里统一指定视图
        public void postHandle(HttpServletRequest request,
                HttpServletResponse response, Object handler,
                ModelAndView modelAndView) throws Exception {
            
            System.out.println("HandlerInterceptor1...postHandle");
            
        }
    
        //执行Handler完成执行此方法
        //应用场景:统一异常处理,统一日志处理
        public void afterCompletion(HttpServletRequest request,
                HttpServletResponse response, Object handler, Exception ex)
                throws Exception {
            
            System.out.println("HandlerInterceptor1...afterCompletion");
        }
    
    }
    @Controller
    public class LoginController {
    
        // 登陆
        @RequestMapping("/login")
        public String login(HttpSession session, String username, String password)
                throws Exception {
    
            // 调用service进行用户身份验证
            // ...
            System.out.println("用户名是:"+username);
            // 在session中保存用户身份信息
            session.setAttribute("username", username);
            // 重定向到商品列表页面
            return "redirect:/items/queryItems";
        }
    
        // 退出
        @RequestMapping("/logout")
        public String logout(HttpSession session) throws Exception {
    
            // 清除session
            session.invalidate();
    
            // 重定向到商品列表页面
            return "redirect:/items/queryItems";
        }

     额外内容:访问Webapp下的静态资源。

    比如在Webapp文件夹下面放了XXX.json。现在访问http://localhost/XXX.json不行,

    需要在web.xml中配置如下:

        <servlet-mapping>
        <servlet-name>default</servlet-name>
        <url-pattern>*.json</url-pattern>
        </servlet-mapping>
  • 相关阅读:
    [XJOI]noip43 T2多人背包
    Codeforces Round #198 (Div. 2)E题解
    [XJOI]noip40 T2统计方案
    Codeforces Round #198 (Div. 2)C,D题解
    Codeforces Round #198 (Div. 2)A,B题解
    9.19[XJOI] NOIP训练37
    9.18[XJOI] NOIP训练36
    kmp算法详解
    [模板系列] AC自动姬
    luogu1967[NOIP2013D1T3] 货车运输 (最大生成树+LCA)
  • 原文地址:https://www.cnblogs.com/legion/p/9599837.html
Copyright © 2020-2023  润新知