SpringMVC学习笔记(二)

复习:

springmvc框架:

DispatcherServlet 前端控制器:接收request,进行response

HandlerMapping 处理器映射器:根据url查找Handler(通过xml配置方式或注解方式)

HandlerAdapter 处理器适配器:决定了用何种特定规则去编写和之后执行Handler。

Handler处理器(后端控制器):需要程序员编写,常用注解开放方式。

Handler处理器执行后结果是ModelAndView,具体开发是Handler返回方法值类型包括:

ModelAndView

String(逻辑视图名)

void(通过在Handler形参中添加request和response,类似原始Servlet开发,注意:可以通过指定response响应的结果类型实现json数据传输)

经过处理器适配器后都会变成ModelAndView

ViewResolver视图解析器:根据逻辑视图名生成真正的视图(在springmvc中使用View对象表示)

注解开发:

使用注解方式的处理器映射器和适配器:

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

在实际开发中,使用< mvc:annotation-driven> 代替上边处理器映射器和适配器配置。

  • @controller 注解必须要加,作用:标识一个Handler处理器。
  • @requestMapping 注解必须要加,作用:

    1、对url和Handler的方法进行映射。

    2、可以窄化请求映射,设置Handler的根路径,URL就是根路径+自路径请求方式

    3、可以限制http请求的方法

    @RequestMapping(value=”/editItems”,method={RequestMethod.POST,RequestMethod.GET})

映射成功后,springmvc框架生成一个Handler对象,对象中只包括一个映射成功的method。

注解开发中参数绑定:

将request请求过来的key/value的数据(理解一个串),通过转换(参数绑定的一部分),将key/value串转成形参,将转换后的结果传给形参(整个参数绑定过程)。

springmvc支持的参数绑定:

1、默认支持很多类型:HttpServlet、response、session、model、modelMap(将模型数据填充到request域)

2、支持简单数据类型,整形、字符型、日期

只要保证request请求的参数名和形参名称一致,自动绑定成功

如果request请求的参数名和形参名称不一致,可以使用@RequestParam(指定request请求的参数名),@RequestParam加在形参的前边。

3、支持pojo类型

只要保证Request请求的参数名称和pojo中的属性名一致,自动将Request请求的参数设置到pojo的属性中。

注意:形参中既有pojo类型又有简单类型,参数绑定互不影响。

自定义参数绑定:

日期类型绑定自定义:

定义Converter<源类型,目标类型> 接口实现类,比如:

Converter< String,Data >表示:将请求的日期数据串转成java中的日期类型。

注意:要转换的目标类型一定和接收的pojo中的属性类型一致。

将定义的Converter实现类注入到处理器适配器中。

<mvc:annotation-driven conversion-service="conversionService">
</mvc:annotation-driven>
<!-- conversionService -->
    <bean id="conversionService"
        class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
        <!-- 转换器 -->
        <property name="converters">
            <list>
                <bean class="cn.itcast.ssm.controller.converter.CustomDateConverter"/>
            </list>
        </property>
    </bean>

springmvc和strut2区别:

springmvc面向方法开发(接近service接口的开发方式),strut2面向类开发。

springmvc可以单例开发,strut2只能是多例开发。

1、Validation校验

b/s系统中对http请求数据的校验多数在客户端进行,这也是出于简单及用户体验性上考虑,但是在一些安全性要求高的系统中服务端校验是不可缺少的,本节主要学习springmvc实现控制层添加校验。

Spring3支持JSR-303验证框架,JSR-303 是JAVA EE 6 中的一项子规范,叫做Bean Validation,官方参考实现是Hibernate Validator(与Hibernate ORM 没有关系),JSR 303 用于对Java Bean 中的字段的值进行验证。

服务端校验:

控制层controller:校验页面请求的参数的合法性。在服务端控制层controller校验,不区分客户端类型(浏览器、手机客户端、远程调用)

业务层service(使用较多):主要校验关键业务参数,仅限于service接口中使用的参数。

持久层dao:一般是不校验的。

1.1 需求

在商品信息修改提交时对商品信息内容进行校验,例如商品名称必须输入,价格合法性校验。

1.2 加入jar包

hibernate的校验框架validation所需要jar包:

1.3 配置校验器

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>

1.4 将validator加到处理器适配器

1.4.1 方式一

增加 validator=”validator” 属性

<mvc:annotation-driven validator="validator"> </mvc:annotation-driven>

1.4.2 方式二

<!-- 自定义webBinder -->
    <bean id="customBinder"
        class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer">
        <property name="validator" ref="validator" />
    </bean>
<!-- 注解适配器 -->
    <bean
        class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
        <property name="webBindingInitializer" ref="customBinder"></property>
    </bean>

1.5 添加验证规则

public class Items {
    //验证明名称在1到30字符中间
    //message是提示校验出错显示的信息
    @Size(min=1,max=30,message="{items.name.length.error}")
    private String name;

    //非空验证
    @NotNull(message="{items.createtime.isNull}")
    private Date createtime;

...

1.6 CustomValidationMessages.properties

在classpath下,新建CustomValidationMessages.properties文件,配置校验错误信息:

#添加校验错误提交信息
items.name.length.error=请输入1到30个字符的商品名称
items.createtime.isNull=请输入商品的生产日期

如果在eclipse中编辑properties文件无法看到中文则参考“Eclipse开发环境配置-indigo.docx”添加propedit插件。

1.7 捕获错误

修改Controller方法:

    @RequestMapping("/editItemsSubmit")
    public String editItemsSubmit(Model model,Integer id,@Validated ItemsCustom itemsCustom,BindingResult bindingResult) throws Exception{
        //获取校验错误信息
        if(bindingResult.hasErrors()){
            //输出错误信息
            List<ObjectError> allErrors=bindingResult.getAllErrors();
            for(ObjectError objectError : allErrors ){
                System.out.println(objectError.getDefaultMessage());
            }
            //将错误信息传到页面
            model.addAttribute("allErrors",allErrors);
            return "items/editItems";
        }

        //调用service更新商品信息,页面需要将商品信息传到此
        itemsService.updateItems(id, itemsCustom);

        return "success";
    }

商品修改页面显示错误信息:

<!-- 显示错误信息 -->
<c:if test="${allErrors!=null }">
    <c:forEach items="${allErrors }" var="error">
        ${error.defaultMessage }
    </c:forEach>
</c:if>

1.8 分组校验

1.8.1需求

在pojo中定义校验规则,而pojo是被多个 controller所共用,当不同的controller方法对同一个pojo进行校验,但是每个controller方法需要不同的校验。

解决方法:

定义多个校验分组(其实是一个java接口),分组中定义有哪些规则

每个controller方法使用不同的校验分组

1.8.2 校验分组

新建接口ValidGroup1.class和ValidGroup2.class

public interface ValidGroup1 {
    //接口中不需要定义任何方法,仅是对不同的校验规则进行分组
    //此分组只校验商品名称长度
}
public interface ValidGroup2 {
    //接口中不需要定义任何方法,仅是对不同的校验规则进行分组
    //此分组只校验商品创建时间为空
}

1.8.3 在验证规则中添加分组

public class Items {

    //验证明名称在1到30字符中间
    //message是提示校验出错显示的信息
    @Size(min=1,max=30,message="{items.name.length.error}",groups={ValidGroup1.class})
    private String name;

    //非空验证
    @NotNull(message="{items.createtime.isNull}",groups={ValidGroup2.class})
    private Date createtime;
...
}

1.8.4 在controller方法使用指定分组的校验

@Validated(value={ValidGroup1.class})

public String editItemsSubmit(Model model,Integer id,@Validated(value={ValidGroup1.class}) ItemsCustom itemsCustom,BindingResult bindingResult) throws Exception{
}

在@Validated中添加value={ValidGroup1.class}表示商品修改使用了ValidGroup1分组校验规则,也可以指定多个分组中间用逗号分隔,

@Validated(value={ValidGroup1.class,ValidGroup2.class })

1.9 校验注解

@Null 被注释的元素必须为 null

@NotNull 被注释的元素必须不为 null

@AssertTrue 被注释的元素必须为 true

@AssertFalse 被注释的元素必须为 false

@Min(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值

@Max(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值

@DecimalMin(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值

@DecimalMax(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值

@Size(max=, min=) 被注释的元素的大小必须在指定的范围内

@Digits (integer, fraction) 被注释的元素必须是一个数字,其值必须在可接受的范围内

@Past 被注释的元素必须是一个过去的日期

@Future 被注释的元素必须是一个将来的日期

@Pattern(regex=,flag=) 被注释的元素必须符合指定的正则表达式

Hibernate Validator 附加的 constraint

@NotBlank(message =) 验证字符串非null,且长度必须大于0

@Email 被注释的元素必须是电子邮箱地址

@Length(min=,max=) 被注释的字符串的大小必须在指定的范围内

@NotEmpty 被注释的字符串的必须非空

@Range(min=,max=,message=) 被注释的元素必须在合适的范围内

2、数据回显

表单提交失败需要再回到表单页面重新填写,原来提交的数据需要重新在页面上显示。

2.1 简单数据类型

对于简单数据类型,如:Integer、String、Float等使用Model将传入的参数再放到request域实现显示。

    @RequestMapping(value="/editItems",method={RequestMethod.GET})
    public String editItems(Model model,Integer id)throws Exception{

        //传入的id重新放到request域
        model.addAttribute("id", id);

2.2 pojo类型

springmvc默认支持pojo数据回显,springmvc自动将形参中的pojo重新放回request域中,request的key为pojo的类名(首字母小写),如下:

controller方法:

    @RequestMapping("/editItemSubmit")
    public String editItemSubmit(Integer id,ItemsCustom itemsCustom)throws Exception{

springmvc自动将itemsCustom放回request,相当于调用下边的代码:

model.addAttribute(“itemsCustom”, itemsCustom);

jsp页面:

<tr>
    <td>商品名称</td>
    <td><input type="text" name="name" value="${itemsCustom.name }"/></td>
</tr>
<tr>
    <td>商品价格</td>
    <td><input type="text" name="price" value="${itemsCustom.price }"/></td>
</tr>

页面中的从“itemsCustom”中取数据。

如果key不是pojo的类名(首字母小写),可以使用@ModelAttribute完成数据回显。

@ModelAttribute作用如下:

1、绑定请求参数到pojo并且暴露为模型数据传到视图页面

此方法可实现数据回显效果。

// 商品修改提交
    @RequestMapping("/editItemSubmit")
    public String editItemSubmit(Model model,@ModelAttribute("item") ItemsCustom itemsCustom)

页面:

<tr>
    <td>商品名称</td>
    <td><input type="text" name="name" value="${item.name }"/></td>
</tr>
<tr>
    <td>商品价格</td>
    <td><input type="text" name="price" value="${item.price }"/></td>
</tr>

如果不用@ModelAttribute也可以使用model.addAttribute(“item”, itemsCustom)完成数据回显。

2、将方法返回值暴露为模型数据传到视图页面

没有@RequestMapping

//商品分类
    @ModelAttribute("itemtypes")
    public Map<String, String> getItemTypes(){

        Map<String, String> itemTypes = new HashMap<String,String>();
        itemTypes.put("101", "数码");
        itemTypes.put("102", "母婴");

        return itemTypes;
    }

页面:

不用通过url请求,页面上可直接得到itemtypes数据

商品类型:
<select name="itemtype">
    <c:forEach items="${itemtypes }" var="itemtype">
        <option value="${itemtype.key }">${itemtype.value }</option>
    </c:forEach>
</select>

3、 异常处理

3.1 异常处理思路

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

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

3.2 自定义异常类

对不同的异常类型定义异常类,继承Exception。

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;
    }
}

3.3 自定义异常处理器

全局异常处理器处理思路:
    解析出异常类型
    如果该 异常类型是系统 自定义的异常,直接取出异常信息,在错误页面展示
    如果该 异常类型不是系统 自定义的异常,构造一个自定义的异常类型(信息为“未知错误”)
public class CustomExceptionResolver implements HandlerExceptionResolver{

    @Override
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler,
            Exception ex) {
        //ex就是系统抛出的异常
        ex.printStackTrace();

        CustomException customException=null;

        //如果抛出的是系统自定义异常则直接转换
        if(ex instanceof CustomException){
            customException=(CustomException)ex;
        }else{
            //如果抛出的不是系统自定义异常则重写构造一个位置错误异常
            customException=new CustomException("未知错误,请与系统管理员联系!");
        }

        ModelAndView modelAndView=new ModelAndView();

        modelAndView.addObject("message",customException.getMessage());
        modelAndView.setViewName("error");

        return modelAndView;
    }

}

3.4 错误页面

<%@ 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>

3.5 异常处理器配置

在springmvc.xml中添加:

    <!-- 全局异常处理器配置 -->
    <!-- 不用配ID,只要实现HandlerExceptionResolver接口就是全局异常处理器 -->
    <bean  class="cn.itcast.ssm.exception.CustomExceptionResolver"/>

3.6 异常测试

如果与业务功能相关的异常,建议在service中抛出异常。

与业务功能没有关系的异常,建议在controller中抛出。

在service接口中抛出异常:

    @Override
    public ItemsCustom findItemsById(Integer id) throws Exception {
        Items items=itemsMapper.selectByPrimaryKey(id);
        if(items==null){
            throw new CustomException("修改的商品信息不存在!");
        }

4、 上传图片

4.1 配置虚拟目录

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

<Context docBase="F:\develop\upload\temp" path="/pic" reloadable="false"/>

访问http://localhost:8080/pic 即可访问 F:\develop\upload\temp下的图片。

也可以通过eclipse配置:

4.2 配置解析器

在 页面form中提交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>

4.3 jar包

CommonsMultipartResolver解析器依赖commons-fileupload和commons-io,加入如下jar包:

4.4 controller

修改:商品修改controller方法:

方法形参增加 MultipartFile items_pic 项

    @RequestMapping("/editItemsSubmit")
    public String editItemsSubmit(Model model,Integer id,@Validated(value={ValidGroup1.class}) ItemsCustom itemsCustom,BindingResult bindingResult,MultipartFile items_pic) throws Exception{
        //获取校验错误信息
        if(bindingResult.hasErrors()){
            //输出错误信息
            List<ObjectError> allErrors=bindingResult.getAllErrors();
            for(ObjectError objectError : allErrors ){
                System.out.println(objectError.getDefaultMessage());
            }
            //将错误信息传到页面
            model.addAttribute("allErrors",allErrors);
            return "items/editItems";
        }

        String originalFilename=null;
        if(items_pic!=null){
            originalFilename=items_pic.getOriginalFilename();
        }
        //上传图片
        if(originalFilename!=null && originalFilename.length()>0){
            //存储图片的物理路径
            String pic_path="C:\\Users\\zxm\\Pictures\\";

            //新的图片名称
            String newFileName=UUID.randomUUID()+originalFilename.substring(originalFilename.lastIndexOf("."));
            //新图片
            File newFile=new File(pic_path+newFileName);

            //将内存中的数据写入磁盘
            items_pic.transferTo(newFile);
            //将新图片名称写到itemsCustom中
            itemsCustom.setPic(newFileName);
        }

        //调用service更新商品信息,页面需要将商品信息传到此
        itemsService.updateItems(id, itemsCustom);

        return "success";
    }

4.5 页面

form添加enctype=”multipart/form-data”

注意:file的name与controller形参一致:

<tr>
    <td>商品图片</td>
    <td>
        <c:if test="${itemsCustom.pic!=null }">
            <img src="/pic/${itemsCustom.pic }" width=100 height=100 />
        </c:if>
        <input type="file" name="items_pic" />
    </td>
</tr>

5、 json数据交互

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

5.1 环境准备

5.1.1 jar包

springmvc 中使用以下jar包进行json转换(@RequestBody 和 @ResponseBody 使用)

5.1.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 /> 则不用定义上边的内容。

5.2 @RequestBody

作用:

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

本例子应用:

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

5.3 @ResponseBody

作用:

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

本例子应用:

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



5.4 请求是json,响应json实现:

5.4.1 jsp页面

...
<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.action‘,
        contentType:‘application/json;charset=utf-8‘,
        //数据格式是json串,商品信息
        data:‘{"name":"手机","price":999}‘,
        success:function(data){//返回json结果
            alert(data.name);
        }
    });
}
</script>
</head>
<body>
<input type="button" onclick="requestJson()" value="请求json,输出是json"/>
</body>

5.4.2 controller页面

@Controller
public class JsonTest {
    //请求json串(商品信息),响应json(商品信息)
    //@RequestBody 将请求的商品信息json串转换成itemsCustom对象
    //@ResponseBody 将返回的itemsCustom对象转化成json 返回
    @RequestMapping("/requestJson")
    public @ResponseBody ItemsCustom requestJson(@RequestBody ItemsCustom itemsCustom){

        return itemsCustom;
    }
    ...
}

5.5 请求是key/value,响应json实现:

5.5.1 jsp页面

...
<script type="text/javascript" src="${pageContext.request.contextPath }/js/jquery-1.4.4.min.js"></script>
//请求key/value,输出json
function responseJson(){
    $.ajax({
        type:‘post‘,
        url:‘${pageContext.request.contextPath }/responseJson.action‘,
        //请求的是key/value是默认格式,不用设置contentType
        //contentType:‘application/json;charset=utf-8‘,
        //数据格式是key/value,商品信息
        data:‘name=手机&price=999‘,
        success:function(data){//返回json结果
            alert(data.name);
        }
    });
}
</head>
<body>
<input type="button" onclick="responseJson()" value="请求key/value,输出是json"/>
</body>

5.5.2 controller页面

输入的key/value 直接可映射为pojo形参,返回的对象需要通过 @ResponseBody 转换为 json数据

@Controller
public class JsonTest {

    //请求key/value(商品信息),响应json(商品信息)
    @RequestMapping("/responseJson")
    public @ResponseBody ItemsCustom responseJson(ItemsCustom itemsCustom){

        return itemsCustom;
    }
}

实际开发中常用第二种方法,请求key/value数据,响应json结果,方便客户端对结果进行解析。

6、 RESTful支持

RESTful架构,就是目前最流行的一种互联网软件架构。它结构清晰、符合标准、易于理解、扩展方便,所以正得到越来越多网站的采用。

RESTful(即Representational State Transfer的缩写)其实是一个开发理念,是对http的很好的诠释。

1、对url进行规范,写RESTful格式的url

非REST的url:http://…../queryItems.action?id=001&type=T01

REST的url风格:http://…./items/001

特点:url简洁,将参数通过url传到服务端

2、http的方法规范

不管是删除、添加、更新。。使用url是一致的,如果进行删除,需要设置http的方法为delete,同理添加。。。

后台controller方法:判断http方法,如果是delete执行删除,如果是post执行添加。

3、对http的contentType规范

请求时指定contentType,要json数据,设置成json格式的type。。

6.1 例子

实现1、3点

6.1.1 需求

查询商品信息,返回json数据

6.1.2 controller

定义方法,进行url映射使用REST风格的URL,将查询商品信息的id传入controller。

输出json使用 @ResponseBody 将返回的java对象转换为json格式返回。

    //查询商品信息,输出json
    // /itemsView/{id} 里的{id} 表示将这个位置的参数要传到@PathVariable指定名称中。
    @RequestMapping("/itemsView/{id}")
    public @ResponseBody ItemsCustom itemsView(@PathVariable("id") Integer id)throws Exception{
        //调用service查询商品信息
        ItemsCustom itemsCustom=itemsService.findItemsById(id);
        return itemsCustom;
    }

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

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

如果RequestMapping中表示为”/ itemsView /{id}”,id和形参名称一致,@PathVariable不用指定名称。

6.1.3 REST方法的前端控制器配置

由于REST方式的URL不以 .action 结尾,所有要单独配置 前端控制器

在web.xml配置:

    <!-- springmvc,REST方式前端控制器 -->
    <servlet>
        <servlet-name>springmvc_test</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <!-- contextConfigLocation配置springmvc加载的配置文件(配置处理器映射器、适配器等) 如果不配置contextConfigLocation,默认加载的是/WEB-INF/servlet名称-servlet.xml(springmvc-servlet.xml) -->
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:spring/springmvc.xml</param-value>
        </init-param>
        <!-- 表示servlet随服务启动 -->
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>springmvc_test</servlet-name>
        <!-- 第一种:*.action,访问以.action 结尾时由此servlet进行解析 第二种:/,所有访问的地址都由此servlet进行解析,如果是静态文件(jpg,js,css)需要配置不让DispatcherServlet进行解析,使用此种方法可以实现RESTful风格的url
            第三种:/*,此设置方法错误,因为请求到Action,当action转到jsp时再次被拦截,提示不能根据jsp路径mapping成功 -->
        <url-pattern>/</url-pattern>
    </servlet-mapping>

6.2 对静态资源的解析

在 springmvc.xml 中添加静态资源解析方法,使得可以通过url访问目录中的静态资源

    <!-- 静态资源解析,包括:js、css、img、... -->
    <mvc:resources location="/js/" mapping="/js/**"/>
    <mvc:resources location="/img/" mapping="/img/**"/>

7、拦截器

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

7.1 拦截器定义

实现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 {

    }

}

7.2 拦截器配置

7.2.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"/>

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

springmvc配置类似全局的拦截器,springmvc框架将配置的类似全局的拦截器注入到每个HandlerMapping中。

springmvc.xml

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

7.3 拦截测试

测试多个拦截器各各方法执行时机。

编写两个拦截

7.3.1 两个拦截器都放行

HandlerInterceptor1…preHandle

HandlerInterceptor2…preHandle

HandlerInterceptor2…postHandle

HandlerInterceptor1…postHandle

HandlerInterceptor2…afterCompletion

HandlerInterceptor1…afterCompletion

总结:

preHandle方法按顺序执行,

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

7.3.2 拦截器1放行,拦截器2不放行

HandlerInterceptor1…preHandle

HandlerInterceptor2…preHandle

HandlerInterceptor1…afterCompletion

总结:

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

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

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

7.3.3 拦截器1不放行,拦截器2不放行(或不放行)

HandlerInterceptor1…preHandle

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

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

7.3.4 总结

preHandle按拦截器定义顺序调用

postHandler按拦截器定义逆序调用

afterCompletion按拦截器定义逆序调用

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

afterCompletion只有preHandle返回true才调用

比如:统一日志处理拦截器,需要该 拦截器preHandle一定要放行,且将它放在拦截器链接中第一个位置。

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

7.4 拦截器应用(实现登陆认证)

7.4.1 需求

1、用户请求url

2、拦截器进行拦截校验

如果请求的url是公开地址(无需登陆即可访问的url),让放行

如果用户session 不存在跳转到登陆页面

如果用户session存在放行,继续操作。

7.4.2 登陆controller方法

LoginController.java

@Controller
public class LoginController {
    //登陆
    @RequestMapping("/login")
    public String login(HttpSession session,String username,String password) throws Exception{
        //调用service进行用户身份验证
        //...

        session.setAttribute("username", username);
        //重定向到商品列表页面
        return "redirect:/items/queryItems.action";
    }

    //退出
    @RequestMapping("/logout")
    public String logout(HttpSession session) throws Exception{
        //清楚session
        session.invalidate();
        return "redirect:/items/queryItems.action";
    }
}

7.4.3 登陆认证拦截器

LoginInterceptor.java

public class LoginInterceptor implements HandlerInterceptor{

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object arg2) throws Exception {
        //获取请求URL
        String url=request.getRequestURI();
        //判断url是否是公开地址,(实际使用时在配置文件获取),这里设为登陆地址
        if(url.indexOf("login.action")>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;
    }

    @Override
    public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3)
            throws Exception {
    }

    @Override
    public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3)
            throws Exception {
    }
}
时间: 2024-10-14 07:29:03

SpringMVC学习笔记(二)的相关文章

springMVC学习笔记(二)-----注解和非注解入门小程序

最近一直在做一个电商的项目,周末加班,忙的都没有时间更新博客了.终于在上周五上线了,可以轻松几天了.闲话不扯淡了,继续谈谈springMvc的学习. 现在,用到SpringMvc的大部分使用全注解配置,但全注解配置也是由非注解发张而来的.所以,今天就谈谈springMvc最基础的注解和非注解的配置以及开发模式. 一:基础环境准备 1.功能需求:一个简单的商品列表查询 2.开发环境:eclipse,java1.7,springmvc版本:3.2 3.springMvc所需jar包(一定包括spri

SpringMVC学习笔记二:常用注解

转载请注明原文地址:http://www.cnblogs.com/ygj0930/p/6831976.html  一.用于定义类的注解:@Controller @Controller 用于标记在一个类上,使用它标记的类就是一个Controller 对象. DispatcherServlet将会扫描使用了该注解的类的方法,并检测方法是否使用了@RequestMapping 注解.@Controller 只是定义了一个控制器类,而使用@RequestMapping 注解的方法才是真正处理请求的处理器

springMVC学习笔记二

六.springmvc的注解 xml的配置→注解 1.新建一个配置文件还是在config下 新建springAnnotation-servlet.xml web.xml 修改初始化为<param-value>classpath*:config/springAnnotation-servlet.xml</param-value> springAnnotation-servlet.xml 加入一个扫描包.扫描包下的所有类 <context:component-scan base-

SpringMVC 学习笔记(二) @RequestMapping、@PathVariable等注解

1.1. @RequestMapping映射请求 SpringMVC 使用 @RequestMapping 注解为控制器指定可以处理那些URL 请求 @requestMapping  可以定义在 类 和 方法 上 package com.ibigsea.springmvc.helloworld; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.Requ

springMVC学习笔记汇总(持续更新)

SpringMVC 学习笔记(一) Hello World SpringMVC 学习笔记(二) @RequestMapping.@PathVariable等注解 SpringMVC 学习笔记(三) 使用ServletAPI 和 实体 做为参数 SpringMVC 学习笔记(四) 处理模型数据 SpringMVC 学习笔记(五) 基于RESTful的CRUD SpringMVC 学习笔记(六) 数据绑定和JSR校验 SpringMVC 学习笔记(七) JSON返回:HttpMessageConve

SpringMVC学习笔记(二): 日常使用功能

前提: 1.web.xml 和spring-mvc核心配置如:SpringMVC学习笔记(一): 基础知识中注解实现. 2.类的@RequestMapping(value="/annotationController") 3.spring-mvc 推荐使用注解实现. 一.数据的接收 (一)URL参数数据的接收 1.使用 HttpServletRequest 获取参数 <span style="font-size:18px;"><span style

史上最全的SpringMVC学习笔记

SpringMVC学习笔记---- 一.SpringMVC基础入门,创建一个HelloWorld程序 1.首先,导入SpringMVC需要的jar包. 2.添加Web.xml配置文件中关于SpringMVC的配置 <!--configure the setting of springmvcDispatcherServlet and configure the mapping--> <servlet> <servlet-name>springmvc</servlet

springmvc学习笔记--REST API的异常处理

前言: 最近使用springmvc写了不少rest api, 觉得真是一个好框架. 之前描述的几篇关于rest api的文章, 其实还是不够完善. 比如当遇到参数缺失, 类型不匹配的情况时, 直接抛出异常, 返回的内容是500+的错误页面, 而不是json内容, 这让移动端的调用方很难处理. 本文主要讲述对于rest api, springmvc对异常的解决处理方案. 系列整理: springmvc学习笔记系列的文章目录: • idea创建springmvc项目 • 面向移动端的REST API

Caliburn.Micro学习笔记(二)----Actions

Caliburn.Micro学习笔记(二)----Actions 上一篇已经简单说了一下引导类和简单的控件绑定 我的上一个例子里的button自动匹配到ViewModel事件你一定感觉很好玩吧 今天说一下它的Actions,看一下Caliburn.Micro给我们提供了多强大的支持 我们还是从做例子开始 demo的源码下载在文章的最后 例子1.无参数方法调用 点击button把textBox输入的文本弹出来 如果textbox里没有文本button不可点,看一下效果图 看一下前台代码 <Stac

2. 蛤蟆Python脚本学习笔记二基本命令畅玩

2. 蛤蟆Python脚本学习笔记二基本命令畅玩 本篇名言:"成功源于发现细节,没有细节就没有机遇,留心细节意味着创造机遇.一件司空见惯的小事或许就可能是打开机遇宝库的钥匙!" 下班回家,咱先来看下一些常用的基本命令. 欢迎转载,转载请标明出处:http://blog.csdn.net/notbaron/article/details/48092873 1.  数字和表达式 看下图1一就能说明很多问题: 加法,整除,浮点除,取模,幂乘方等.是不是很直接也很粗暴. 关于上限,蛤蟆不太清楚