SpringMVC基础知识(3)

1、包装类型pojo参数绑定

      1.1、需求:

      商品查询controller方法中实现商品查询条件传入。

      1.2、实现方法

      第一种方法:在形参中添加HttpServletRequest request参数,通过request接收查询条件参数。

      第二种方法:在形参中让包装类型的pojo接收查询条件参数。

      分析:

      页面传参数的特点:复杂、多样性。

      如果将用户账号、商品编号、订单信息等放在简单pojo(属性是简单类型)中,pojo类属性比较多,比较乱。

      建议使用包装类型的pojo,pojo中属性是pojo。

      1.3、页面参数和controller方法形参定义

      页面参数:

<form action="${pageContext.request.contextPath }/items/queryItems.action" method="post">
查询条件:
<table width="100%" border=1>
<tr>
<td>
商品名称:<input name="itemsCustom.name"/>
</td>
<td><input type="submit" value="查询"/></td>
</tr>
      controller方法形参:

    @RequestMapping("/queryItems")
    public ModelAndView queryItems(HttpServletRequest request, ItemsQueryVo itemsQueryVo) throws Exception{
 
      

2、集合类型绑定

      2.1、数组绑定

      2.1.1、需求:
      商品批量删除,用户在页面选择多个商品,批量删除。
      2.1.2、表现层实现
      关键:将页面选择(多选)的商品id,传到controller方法的形参,方法形参使用数组接收页面请求的多个商品id。
      controller方法定义:
    //批量删除商品信息
    @RequestMapping("/deleteItems")
    public String deleteItems(Integer[] items_id) throws Exception{
      2.1.3、页面定义:
商品列表:
<table width="100%" border=1>
<tr>
	<td>选择</td>
	<td>商品名称</td>
	<td>商品价格</td>
	<td>生产日期</td>
	<td>商品描述</td>
	<td>操作</td>
</tr>
<c:forEach items="${itemsList }" var="item">
<tr>
	<td><input type="checkbox" name="items_id" value="${item.id }"/></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 }/items/editItems.action?id=${item.id}">修改</a></td>

</tr>
</c:forEach>

      2.2、list绑定

      2.2.1、需求:
      通常在需要批量提交数据时,将提交的数据绑定到list<pojo>中。例如:成绩录入(录入多门课成绩,批量提交)
      本例需求:批量修改商品信息,在页面输入多个商品信息,将多个商品信息提交到controller方法中。
      2.2.2、表现层实现
      controller方法定义:
      1)进入批量修改商品页面
      2)批量修改商品提交
      使用List接收页面提交的批量数据,通过包装pojo接收,在包装pojo中定义list<pojo>属性
public class ItemsQueryVo {

    // 商品信息
    private Items items;

    private ItemsCustom itemsCustom;

    private List<ItemsCustom> itemsList;
      修改商品信息提交的方法:
    //通过ItemsQueryVo接收批量提交的商品信息,将商品信息存储到itemsQueryVo中itemsList属性中
    @RequestMapping("/editItemsAllsubmit")
    public String editItemsAllsubmit(HttpServletRequest request, ItemsQueryVo itemsQueryVo) throws Exception{
  
      页面定义:
      

      2.3、map绑定

      在包装pojo中定义map类型属性。
      在包装类中定义Map对象,并添加get/set方法,action使用包装对象接收。
      包装类中定义Map对象如下:
Public class QueryVo {
private Map<String, Object> itemInfo = new HashMap<String, Object>();
  //get/set方法..
}
      页面定义如下:
<tr>
<td>学生信息:</td>
<td>
姓名:<inputtype="text"name="itemInfo['name']"/>
年龄:<inputtype="text"name="itemInfo['price']"/>
.. .. ..
</td>
</tr>

3、springmvc校验

      3.1、校验理解
      项目中,通常使用较多是前端的校验,比如页面js校验。对于安全要求较高建议在服务端进行校验。
      服务端校验:
      控制层controller:校验页面请求的参数的合法性。在服务端控制层controller校验,不区分客户端类型(浏览器、手机客户端、远程调用)
      业务层service( 使用较多):主要校验关键业务参数,仅限于service接口中使用的参数。
      持久层dao:一般是不校验的。
      3.2、springmvc校验需求
      springmvc使用Hibernate的校验框架validation(和Hibernate没有任何关系)
      校验思路:
      页面提交请求的参数,请求到controller方法中,使用validation进行校验。如果校验出错,将错误信息展示到页面。
      具体需求:
      商品修改,添加校验(校验商品名称长度,生产日期的非空校验),如果校验出错,在商品修改页面显示错误信息。
      3.3、添加校验框架validation所需要的jar包
      
      3.4、在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>
      3.5、将校验器注入到处理器适配器中
      
      3.6、在pojo中添加校验规则
      在Items.java中添加校验规则:
      
      3.7、配置校验错误信息
      创建CustomValidationMessages.properties,配置校验错误信息:
      
      3.8、捕获校验错误信息
      ☆:在需要校验的pojo前边添加@Validated,在需要校验的pojo后边添加BindingResult  bindingResult接收校验出错信息。
      注意:@Validated和BindingResult  bindingResult是配对出现的,并且形参顺序是固定的。
      
      3.9、在页面显示校验错误信息
      在controller中将错误信息传到页面:
      
      在页面中显示错误信息:
      
      3.10、分组校验
      3.10.1、需求:
      在pojo中定义校验规则,而pojo是被多个controller所共用,当不同的controller方法对同一个pojo进行校验,但是每个controller方法需要不同的校验。
      解决方法:
      定义多个校验分组(其实是一个java接口),分组中定义有哪些规则
      每个controller方法使用不同的校验分组
      3.10.2、创建校验分组
      
      3.10.3、在校验规则中添加分组
      
      3.10.4、在controller中使用指定分组的校验
      

4、数据回显

      4.1、什么数据回显?
      提交后,如果出现错误,将刚才提交的数据回显到刚才的提交页面。
      4.2、pojo数据回显方法
      1)springmvc默认对pojo数据进行回显。
      pojo数据传入controller方法后,springmvc自动将pojo数据放到request域,key等于pojo类型(首字母小写)
      使用@ModelAttribute指定pojo回显到页面在request中的key
      2)@ModelAttribute还可以将方法的返回值传到页面
      在商品查询列表页面,通过商品类型查询商品信息。
      在controller中定义商品类型查询方法,最终将商品类型传到页面。
      
      页面上可以得到itemTypes数据:
      
      3)简单方法使用model,可以不用@ModelAttribute
      
      4.3、简单类型数据回显
      使用简单方法model
      model.addAttribute("id",id);

5、异常处理

      5.1、异常处理思路
      系统中异常包括两类:预期异常和运行时异常RuntimeException,前者通过捕获异常从而获取异常信息,后者主要通过规范代码开发、测试等方式减少运行时异常的发生。
      系统的dao、service、controller出现都通过throws Exception向上抛出,最后由springmvc前端控制器交由异常处理器进行处理,如下图:
      
      springmvc提供全局异常处理处理器(一个系统只有一个异常处理器)进行统一异常处理。
      5.2、自定义异常类
      对不同的异常类型定义异常类,继承Exception。
package lsq.study.ssm.exception;

/**
 * 系统自定义异常类,针对预期的异常,需要在程序中抛出此类的异常
 * @author lsq
 *
 */
public class CustomException extends Exception {

    // 异常信息
    public String message;

    public CustomException(String message) {
        super(message);
        this.message = message;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

}
      5.3、全局异常处理器
      思路:
      系统遇到异常,在程序中手动抛出,dao抛给service,service抛给controller,controller抛给前端控制器,前端控制器调用全局异常处理器。
      全局异常处理器处理思路:
      1)解析出异常类型
      2)如果该异常类型是系统自定义异常,直接取出异常信息,在错误页面显示
      3)如果该异常类型不是系统自定义异常,构造一个自定义的异常类型(信息为“未知错误”)
      ☆:springmvc提供了一个HandlerExceptionResolver接口
package lsq.study.ssm.exception;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;

/**
 * 全局异常处理类
 * @author lsq
 *
 */
public class CustomExceptionResolver implements HandlerExceptionResolver{

    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler,
            Exception ex) {
        //handler就是处理器适配器要执行的handler对象(只有method)
        
//        1)解析出异常类型
//        2)如果该异常类型是系统自定义异常,直接取出异常信息,在错误页面显示
//        String message = null;
//        if(ex instanceof CustomException){
//            message = ((CustomException)ex).getMessage();
//        }else {
        3)如果该异常类型不是系统自定义异常,构造一个自定义的异常类型(信息为“未知错误”)
//            message = "未知错误";
//        }
        
        //对上边的代码进行修改
        CustomException customException = null;
        if(ex instanceof CustomException){
            customException = (CustomException)ex;
        }else{
            customException = new CustomException("未知错误");
        }
        
        //获取错误信息
        String message = customException.getMessage();
        
        ModelAndView modelAndView = new ModelAndView();
        
        //将错误信息传递到页面
        modelAndView.addObject("message", message);
        
        //指向错误页面
        modelAndView.setViewName("error");
        
        return modelAndView;
    }

}
      5.4、错误提示页面
      
      5.5、在springmvc.xml配置全局异常处理器
	<!-- 
		全局异常处理器:
		只要实现HandlerExceptionResolver接口就是全局异常处理器
	 -->
	<bean class="lsq.study.ssm.exception.CustomExceptionResolver"></bean>
      5.6、异常测试
      在controller、service、dao中任意一处需要手动抛出异常。
      如果是程序手动抛出的异常,在错误页面中显示自定义的异常信息,如果不是手动抛出异常说明是一个运行时异常,在错误页面只显示“未知错误”。
      在商品修改的controller方法中抛出异常:
      
      在service接口中抛出异常:
      
      总结:
      如果与业务功能相关的异常,建议在service中抛出异常。
      与业务功能没有关系的异常,建议在controller中抛出异常。

6、上传图片

      6.1、需求:
      在修改商品页面,添加上传商品图片功能。
      6.2、springmvc中对多部件类型解析
      在页面中提交enctype="multipart/form-data"的数据时,需要springmvc对multipart类型的数据进行解析。
      在springmvc.xml中配置multipart类型解析器:
	<!-- 文件上传 -->
	<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
		<!-- 设置上传文件的最大尺寸为5MB -->
		<property name="maxUploadSize">
			<value>5242880</value>
		</property>
	</bean>
      6.3、加入上传图片的jar包
      
      6.4、创建图片虚拟目录存储图片
      通过图形界面配置:
      
      也可以直接修改tomcat的配置:
      在conf/server.xml文件中,添加虚拟目录:
      
      注意:在图片虚拟目录中,一定将图片目录分级创建(提高i/o性能),一般我们采用按照日期(年、月、日)进行分级创建。
      6.5、上传图片代码:
      6.5.1、页面
      
      6.5.2、controller方法
      
      

7、json数据交互

      7.1、为什么要进行json数据交互?

      json数据格式在接口调用中、html页面中较常用,json格式比较简单,解析比较方便。
      比如:webservice接口,传输json数据。

      7.2、springmvc进行json交互

      
      ☆:注意
      1)请求json、输出json,要求请求的是json串,所以在前端页面中需要将请求的内容转成json,不方便。
      2)请求key/value、输出json。此方法比较常用。

      7.3、环境准备

      7.3.1、加载json使用的jar包
      springmvc中使用jackson的包进行json转换(@requestBody和@responseBody使用下边的包进行json转换),如下:
      
      7.3.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/>,则不用定义上边的内容。

      7.4、json交互测试

      7.4.1、输入json串,输出json串
      1)jsp页面:
      使用jquery的ajax提交json串,对输出的json结果进行解析。
      
      2)controller定义
      
      3)测试结果:
      
      7.4.2、输入key/value,输出json串
      1)jsp页面
      
      2)controller方法
      
      3)测试结果
      

8、RESTful支持

      8.1、什么是RESTful?
      RESTful架构是目前最流行的一种互联网软件架构。它结构清晰、符合标准、易于理解、扩展方便。
      1)对url进行规范,写RESTful格式的url
      特点:url简洁,将参数通过url传递到服务端
      2)http的方法规范
      不管是删除、添加、更新。使用url是一致的,如果进行删除,需要设置http方法为delete。。。
      后台controller方法:判断http方法,如果是delete,执行删除,如果是post,执行添加。
      8.2、RESTful的例子
      8.2.1、需求:查询商品信息,返回json数据
      8.2.2、controller方法定义:
      定义方法,进行url映射使用REST风格的url,将查询商品信息的id传入controller,
      输出json使用@responseBody将java对象输出为json
      
      @PathVariable用于将请求URL中的模板变量映射到功能处理方法的参数上。
      如果@RequestMapping中表示为"/itemsView/{id}",id和形参名称一致,@PathVariable不用指定名称。
      8.2.3、REST方法的前端控制器配置
      在web.xml中配置:
      
      8.3、对静态资源的解析
      配置前端控制器的url-parttern中指定/,对静态资源的解析出现问题:
      
      解决办法:
      在springmvc.xml文件中添加静态资源解析方法
      

9、拦截器

      9.1、拦截器的定义
      定义拦截器,实现HandlerInterceptor接口。接口中提供三个方法:
package lsq.study.ssm.interceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

public class HandlerInterceptor1 implements HandlerInterceptor{

    //进入Handler方法之前执行
    //用于身份认证、身份授权
    //比如身份认证,如果认证不通过表示当前用户没有登录,需要此方法拦截不再向下执行
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //return false 表示拦截,不再向下执行
        //return true 表示放行
        return false;
    }
    
    //进入Handler方法之后,返回modelandview之前执行
    //应用场景:(从ModelAndView出发)将公用的模型数据在这里传到视图,也可以在这里统一制定视图
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView mv)
            throws Exception {
        
    }

    //执行Handler完成执行此方法
    //应用场景:统一异常处理,统一日志处理
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
            throws Exception {
        
    }
}
      9.2、拦截器配置
      9.2.1、针对HandlerMapping配置
      springmvc拦截器针对HandlerMapping进行拦截设置,如果在某个HandlerMapping中配置拦截,经过该HandlerMapping映射成功的handler最终使用该拦截器。
<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"/>
      该方法一般不推荐使用。
      9.2.2、类似全局的拦截器配置
      springmvc配置类似全局的拦截器配置,springmvc框架将配置的类似全局的拦截器注入到每个HandlerMapping中。
	<!-- 配置拦截器 -->
	<mvc:interceptors>
		<mvc:interceptor>
			<!-- /**表示所有url包括子url路径 -->
			<mvc:mapping path="/**"/>
			<bean class="lsq.study.ssm.interceptor.HandlerInterceptor1"/>
		</mvc:interceptor>
		<mvc:interceptor>
			<mvc:mapping path="/**"/>
			<bean class="lsq.study.ssm.interceptor.HandlerInterceptor2"/>
		</mvc:interceptor>
	</mvc:interceptors>
      9.3、拦截测试
      9.3.1、测试需求
      测试多个拦截器各个方法执行时机。
      9.3.2、编写两个拦截器
      
      9.3.3、两个拦截器都放行

      HandlerInterceptor1...preHandle

      HandlerInterceptor2...preHandle


      HandlerInterceptor2...postHandle

      HandlerInterceptor1...postHandle

 

      HandlerInterceptor2...afterCompletion

      HandlerInterceptor1...afterCompletion

      总结:

      preHandle方法按顺序执行,

      postHandle和afterCompletion按拦截器配置的逆向顺序执行。

      9.3.4、拦截器1放行,拦截器2不放行

      HandlerInterceptor1...preHandle

      HandlerInterceptor2...preHandle

      HandlerInterceptor1...afterCompletion

      总结:

      拦截器1放行,拦截器2preHandle才会执行。

      拦截器2preHandle不放行,拦截器2postHandle和afterCompletion不会执行。

      只要有一个拦截器不放行,postHandle不会执行。

      9.3.5、拦截器1不放行,拦截器2不放行

      HandlerInterceptor1...preHandle

      总结:

      拦截器1preHandle不放行,postHandle和afterCompletion不会执行。

      拦截器1不执行,拦截器2不执行。

      9.3.6、小结

      根据测试结果,对拦截器应用。

      比如:统一日志处理拦截器,需要该拦截器preHandle一定要放行,且将它放在拦截器链中第一个位置,这样afterCompletion方法才会执行。

      比如:登录认证拦截器,放在拦截器链中第一个位置。权限校验拦截器,放在登录认证拦截器之后。(因为登录通过后才校验权限)


      




      

  


      
      

      


      



      
      

      


      



      

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值