SpringMVC——高级参数绑定(数组、集合),@RequestMapper 的使用,Controller方法的三种返回值类型,异常处理器,上传图片,JSON数据交互,配置拦截器

一.高级参数绑定

1、将前端传来的参数绑定数组/集合中

1)数组直接接收

@RequestMapping(value = "/arrayTest.action")
public void arrayTest(Integer[] ids){
    System.out.println(Arrays.toString(ids));
}

2)POJO中的数组接收

@RequestMapping(value = "/arrayTest.action")
public void arrayTest(QueryVo vo){
    System.out.println(Arrays.toString(vo.getIds()));
}

3)集合直接接收(报错,无法直接接收)

@RequestMapping(value = "/arrayTest.action")
public void arrayTest(List<Integer> ids){
    System.out.println(ids);
}

4)POJO中的集合接收

@RequestMapping(value = "/arrayTest.action")
public void arrayTest(QueryVo vo){
    System.out.println(vo.getIds());
}

2、将前端传来的所有参数保存到集合中

JSP页面样式

SpringMVC——高级参数绑定(数组、集合),@RequestMapper 的使用,Controller方法的三种返回值类型,异常处理器,上传图片,JSON数据交互,配置拦截器

<form action="${pageContext.request.contextPath }/arrayTest.action" method="post">
	商品列表:
	<table width="100%" border=1>
		<tr>
			<td>选择</td>
			<td>商品名称</td>
			<td>商品价格</td>
			<td>生产日期</td>
			<td>商品描述</td>
			<td>操作</td>
		</tr>
		<c:forEach items="${itemList }" var="item" varStatus="s">
			<tr>
				<td><input type="checkbox" name="ids" value="${item.id }"></td>
				<td><input type="text" name="itemsList[${s.index}].name" value="${item.name }"></td>
				<td><input type="text" name="itemsList[${s.index }].price" value="${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>

	</table>

	<input type="submit"/>
</form>

 QueryVO.java

public class QueryVo {

    List<Item> itemsList;

    public List<Item> getItemsList() {
        return itemsList;
    }

    public void setItemsList(List<Item> itemsList) {
        this.itemsList = itemsList;
    }
}

测试类

@RequestMapping(value = "/arrayTest.action")
public void arrayTest(QueryVo vo){
    System.out.println(vo.getItemsList());
}

二.@RequestMapper 

1、URL路由映射

@RequestMapping(value = "/xxx.action")

2、在类上加

// 简化请求路径  /itemList ==> /item/itemList
@RequestMapping("/item")
public class ItemsController {

3、方法限定

限定GET方法:@RequestMapping(method = RequestMethod.GET)

限定POST方法:@RequestMapping(method = RequestMethod.POST)

GETPOST都可以:@RequestMapping(method = {RequestMethod.GET,RequestMethod.POST})

4、多个URL映射到同一方法

@RequestMapping(value = "{/itemList.action,/item123.action}")

三.Controller方法返回值

1、返回ModelAndView

controller方法中定义ModelAndView对象并返回,对象中可添加model数据、指定view。(一般用于异常处理器中)

// 配置请求的url
@RequestMapping(value = "/itemList.action")
public ModelAndView queryItemList(){

    // 创建页面需要显示的商品数据
    List<Item> items = itemService.selectItemsList();

    ModelAndView modelAndView = new ModelAndView();

    // 放到request域中
    modelAndView.addObject("itemList",items);
    //modelAndView.setViewName("/WEB-INF/jsp/itemList.jsp");
    modelAndView.setViewName("itemList");

    return modelAndView;
}

2、返回String

优点:解耦,返回视图路径,model带数据,官方推荐此种方式。解耦,数据,视图,分离,MVC 。

// 配置请求的url
@RequestMapping(value = "/itemList.action")
public String queryItemList(Model model){

    // 创建页面需要显示的商品数据
    List<Item> items = itemService.selectItemsList();

    // 放到request域中
    model.addAttribute("itemList",items);

    //return "itemList";    // 直接返回一个视图文件(jsp)
    //return "redirect:/itemEdit.action?itemId=1";  // 重定向到其他URL
    return "forward: /itemEdit.action?itemId=1";  // 转发到其他URL
}

3、返回Void(常用于ajax)

/ 配置请求的url
@RequestMapping(value = "/itemList.action")
public void queryItemList(HttpServletRequest request, HttpServletResponse response, HttpSession session, Model model,...其他自定义的类) throws ServletException, IOException {

    // 创建页面需要显示的商品数据
    List<Item> items = itemService.selectItemsList();

    request.setAttribute("itemList",items);

    // 请求转发
    request.getRequestDispatcher("/WEB-INF/jsp/itemList.jsp").forward(request,response);
}

四.异常处理器

springmvc在处理请求过程中出现异常信息交由异常处理器进行处理,自定义异常处理器可以实现一个系统的异常处理逻辑。

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

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

SpringMVC——高级参数绑定(数组、集合),@RequestMapper 的使用,Controller方法的三种返回值类型,异常处理器,上传图片,JSON数据交互,配置拦截器

自定义异常处理器

1)自定义一个异常MyException.java

public class MyException extends Exception {

    private String msg;

    public MyException(String msg) {
        this.msg = msg;
    }

    public MyException() {
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }
}

2)在程序中手动抛出这个异常

// 配置请求的url
@RequestMapping(value = "/itemList.action")
public void queryItemList(HttpServletRequest request, HttpServletResponse response, HttpSession session, Model model) throws Exception {

    if (1==1) {
        throw new MyException("啦啦啦");
    }

    // 创建页面需要显示的商品数据
    List<Item> items = itemService.selectItemsList();

    request.setAttribute("itemList",items);

    // 请求转发
    request.getRequestDispatcher("/WEB-INF/jsp/itemList.jsp").forward(request,response);
}

3)在applicationContext.xml中配置全局异常处理器

<!-- *****************配置全局异常处理器***************** -->

<bean class="cn.x5456.exception.CustomExceptionResolver"/>

4)书写异常处理器

import org.springframework.web.servlet.HandlerExceptionResolver;    // 别导错包

public class CustomExceptionResolver implements HandlerExceptionResolver {

    @Override
    public ModelAndView resolveException(HttpServletRequest httpServletRequest,
                                         HttpServletResponse httpServletResponse,
                                         Object o,  // 发生异常的地方 Serivce层  方法  包名+类名+方法名(形参) 字符串
                                         Exception e) {

        ModelAndView mav = new ModelAndView();

        String msg = "未知异常";

        if (e instanceof MyException){
            MyException myex = (MyException) e;
            msg = myex.getMsg();
        }

        mav.addObject("msg",msg);
        mav.setViewName("error");

        return mav;
    }
}

五.上传图片

1)配置上传文件夹的url访问路径

SpringMVC——高级参数绑定(数组、集合),@RequestMapper 的使用,Controller方法的三种返回值类型,异常处理器,上传图片,JSON数据交互,配置拦截器

2)配置applicationContext.xml

<!-- *************配置文件上传的实现类,id必须设置为multipartResolver*************-->

<bean 
      class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    <!-- 设置文件上传大小 -->
    <property name="maxUploadSize" value="5000000" />
</bean>
<!-- 文件上传 -->
    <bean >

        <!-- 设置上传文件的最大尺寸位30M -->
        <property name="maxUploadSize" value="31457280" />
        <property name="defaultEncoding" value="UTF-8" />
        <!-- 是否延迟加载,在需要的时候才进行上传文件的解析 -->
        <property name="resolveLazily" value="true" />
        <!-- 文件上传的临时路径,文件上传完成后,临时目录中的临时文件会被自动清除 -->
        <property name="uploadTempDir" value="upload/temp" />
    </bean>

3)修改form标签

<form >

4)书写Controller

@RequestMapping(value = "/updateitem.action")
public String arrayTest(Item itemPOJO, MultipartFile pictureFile) throws IOException {  // 接收前端传来的pic文件对象
    // 1.保存图片
        // 为避免重复,使用uuid
    String picName = UUID.randomUUID().toString().replaceAll("-", "");
        // 获取文件名的后缀
    String ext = FilenameUtils.getExtension(pictureFile.getOriginalFilename());
        // 保存文件
    pictureFile.transferTo(new File("D:\upload\"+picName+"."+ext));

    // 2.更新商品信息
    itemPOJO.setPic(picName+"."+ext);

    itemService.updateItem(itemPOJO);

    return "redict:/itemEdit.action?id="+itemPOJO.getId();
}

六.JSON数据交互

前端 

<script type="text/javascript" src="${pageContext.request.contextPath }/js/jquery-1.4.4.min.js"></script>
<script type="text/javascript">
    $(function () {

        // 不能使用
        // $.post(url,params,
        // 	function(data){
        //     回调
        // 	},
        // 	"json");	因为这个jasn指的是响应是json格式的数据

        var params = '{"id": 1,"name": "测试商品","price": 99.9,"detail": "测试商品描述","pic": "123456.jpg"}';	// 字典+引号==json字符串

        $.ajax({
            url : "${pageContext.request.contextPath }/json.action",
            data : params,
            contentType : "application/json;charset=UTF-8",//发送数据的格式
            type : "post",
            dataType : "json",//回调
            success : function(data){
                alert(data.name);
            }
        })

    })
</script>

后端

@RequestMapping(value = "/json.action")
public @ResponseBody Item jsonTest(@RequestBody Item item){

    System.out.println(item);

    return item;

}

七.拦截器

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

配置拦截器 

applicationContext.xml

<!-- *************配置拦截器************* -->

<mvc:interceptors>
    <mvc:interceptor>
        <!-- 所有的请求都进入拦截器 -->
        <mvc:mapping path="/**" />
        <!-- 配置具体的拦截器 -->
        <bean class="cn.x5456.interceptor.HandlerInterceptor1" />
    </mvc:interceptor>
    <mvc:interceptor>
        <!-- 所有的请求都进入拦截器 -->
        <mvc:mapping path="/**" />
        <!-- 配置具体的拦截器 -->
        <bean class="cn.x5456.interceptor.HandlerInterceptor2" />
    </mvc:interceptor>
</mvc:interceptors>

HandlerInterceptor1.java

package cn.x5456.interceptor;


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

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

public class HandlerInterceptor1 implements HandlerInterceptor {
    // controller执行后且视图返回后调用此方法
    // 这里可得到执行controller时的异常信息
    // 这里可记录操作日志
    @Override
    public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3)
            throws Exception {
        System.out.println("HandlerInterceptor1....afterCompletion");
    }

    // controller执行后但未返回视图前调用此方法
    // 这里可在返回用户前对模型数据进行加工处理,比如这里加入公用信息以便页面显示
    @Override
    public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, org.springframework.web.servlet.ModelAndView modelAndView) throws Exception {
        System.out.println("HandlerInterceptor1....postHandle");
    }


    // Controller执行前调用此方法
    // 返回true表示继续执行,返回false中止执行
    // 这里可以加入登录校验、权限拦截等
    @Override
    public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception {
		// 获取session  
		// HttpSession session =request.getSession();  
		
        System.out.println("HandlerInterceptor1....preHandle");
        // 设置为true,测试使用
        return true;
    }
    
}

结果

控制台打印:

HandlerInterceptor1..preHandle..

HandlerInterceptor2..preHandle..

HandlerInterceptor2..postHandle..

HandlerInterceptor1..postHandle..

HandlerInterceptor2..afterCompletion..

HandlerInterceptor1..afterCompletion..

处理流程

preHandle按拦截器定义顺序调用

postHandler按拦截器定义逆序调用

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

afterCompletion按拦截器定义逆序调用

  • afterCompletion只有preHandle返回true才调用

SpringMVC与Struts2拦截器的区别

他们的拦截器都是继承servlet的filter;且都能传递了request和response作用域。spring过滤后是去找controller,struts过滤后是去struts的配置文件找action。 

 

// 获取应用的url
request.getScheme() +"://" + request.getServerName() + ":" +request.getServerPort() +request.getContextPath();

// 获取应用的绝对路径
request.getServletContext().getRealPath("/")