SpringMVC框架技术

SpringMVC概述

基本介绍

springmvc是spring框架的一个模块,springmvc和spring无需通过中间整合层进行整合。springmvc是一个基于mvc的web框架。

SpringMVC的执行过程

执行细节

  1. DispatcherServlet处理url请求,并通过处理器映射器(HandlerMapping)找到对应的Handler
  2. 处理器映射器会返回一个执行链(就是一个封装好的对象HandlerExecutionChain),里面包含了Handler以及多个拦截器(HandlerInterceptor)
  3. DispacherServlet不会直接执行Handler,而是请求处理器适配器(HandlerAdapter)去执行,然后HandlerAdapter会返回一个ModelAndView(模型视图对象)对象
  4. DispatcherServlet请求视图解析器(View resolver)对ModelAndView进行解析并返回view
  5. 视图渲染将模型数据填充到request域中
  6. response响应

执行细节(详细版本)

  1. 发起请求到前端控制器(DispatcherServlet)

  2. 前端控制器请求HandlerMapping查找 Handler(可以根据xml配置、注解进行查找)

  3. 处理器映射器HandlerMapping向前端控制器返回Handler

  4. 前端控制器调用处理器适配器去执行Handler

  5. 处理器适配器去执行Handler

  6. Handler执行完成给适配器返回ModelAndView

  7. 处理器适配器向前端控制器返回ModelAndView(ModelAndView是springmvc框架的一个底层对象,包括 Model和view)

  8. 前端控制器请求视图解析器去进行视图解析,根据逻辑视图名解析成真正的视图(jsp)

  9. 视图解析器向前端控制器返回View

  10. 前端控制器进行视图渲染,视图渲染将模型数据(在ModelAndView对象中)填充到request域

  11. 前端控制器向用户响应结果

SpringMVC执行过程中涉及的组件

  1. 前端控制器DispatcherServlet(不需要程序员开发)

    作用:接收请求,响应结果,相当于转发器,中央处理器。DispatcherServlet减少了其它组件之间的耦合度。

  2. 处理器映射器HandlerMapping(不需要程序员开发)

    作用:根据请求的url查找Handler

  3. 处理器适配器HandlerAdapter

    作用:按照特定规则(HandlerAdapter要求的规则)去执行Handler

  4. 处理器Handler(需要程序员开发)

    注意:编写Handler时按照HandlerAdapter的要求去做,这样适配器才可以去正确执行Handler

  5. 视图解析器View resolver(不需要程序员开发)

    作用:进行视图解析,根据逻辑视图名解析成真正的视图(view)

  6. 视图View(需要程序员开发jsp)

    View是一个接口,实现类支持不同的View类型(jsp、freemarker、pdf…)

入门程序

配置步骤(非注解开发版)

配置DispatcherServlet转发器
<!--DispatcherServlet是一个Servlet,需要在web.xml中进行配置-->
<!--配置转发器DispatcherServlet-->
  <servlet>
    <servlet-name>springMvc</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:springMvc.xml</param-value>
    </init-param>
  </servlet>
  <servlet-mapping>
    <servlet-name>springMvc</servlet-name>
    <url-pattern>*.action</url-pattern>
  </servlet-mapping>

注意:

  1. 在配置的时候需要配置init-param,这里是为了初始化Spring容器

  2. 关于url-pattern(Servlet的拦截方式)

    • 拦截固定后缀的url,比如设置为 .do、.action, 例如:/user/add.action

      此方法最简单,不会导致静态资源(jpg,js,css)被拦截。

    • 拦截所有,设置为/,例如:/user/add /user/add.action

      此方法可以实现REST风格的url,很多互联网类型的应用使用这种方式。但是此方法会导致静态文件(jpg,js,css)被拦截后不能正常显示。需要特殊处理。

    • 拦截所有,设置为/*,此设置方法错误,因为请求到Action,当action转到jsp时再次被拦截,提示不能根据jsp路径mapping成功。

配置处理器适配器

在Spring的配置文件中进行配置

<!--配置处理器适配器-->
<bean id="adapter" class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
  1. 处理器适配器可以处理所有实现了Controller接口的类
  2. SimpleControllerHandlerAdapter:即简单控制器处理适配器,所有实现了org.springframework.web.servlet.mvc.Controller 接口的Bean作为SpringMVC的后端控制器。

编写控制器Handler

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/*
	必须实现Controller接口
*/
public class ItemList01 implements Controller {
    @Override
    public ModelAndView handleRequest(javax.servlet.http.HttpServletRequest httpServletRequest, javax.servlet.http.HttpServletResponse httpServletResponse) throws Exception {

        List<Items> list = new ArrayList<>();
        for (int i = 0; i < 3; i++) {
            Items items = new Items();
            items.setPrice((i+1)*120.0f);
            items.setCreatetime(new Date());
            items.setDetail("这是第"+(i+1)+"个作品");
            items.setId(i);
            items.setName("电脑"+i);
            list.add(items);
        }
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.addObject("itemsList",list);
        modelAndView.setViewName("/WEB-INF/jsp/items/itemsList.jsp");
        return modelAndView;
    }
}

编写处理器映射器

在Spring的配置文件中配置

<!--编写处理器映射器-->
<bean id="handlerMapping" class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>

配置编写的处理器

在Spring的配置文件中配置

<!--配置Handler-->
<bean name="/queryList/itemsList.action" class="zzuli.zw.learnSpringMVC.controller.ItemList01"/>

name值将来作为访问路径url

配置试图解析器

在Spring配置文件中配置

<!--配置视图解析器-->
<bean id="resolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"/>

非注解的处理器映射器和处理器适配器

非注解的处理器映射器

在非注解情况下,我们可以使用两种方式的处理器映射器:

  1. <!--编写处理器映射器-->
    <bean id="handlerMapping" class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
    

    这种方式的处理器映射器会根据配置的Handler的name来查找Handler

    此时的Handler配置方式

    <bean name="/queryList/itemsList.action" class="zzuli.zw.learnSpringMVC.controller.ItemList01"/>
    
  2. <bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
        <property name="mappings">
            <props>
                <prop key="/queryList/itemsList02.action">list01</prop>
                <prop key="/query/itemsList.action">list01</prop>
            </props>
        </property>
    </bean>
    

    其中key为url路径,值为配置的Handler的id

    此时的Handler的配置方式

    <!--配置Handler-->
    <bean id="list01" name="/queryList/itemsList.action" class="zzuli.zw.learnSpringMVC.controller.ItemList01"/>
    
  3. 注意:

    • 以上两种适配器并非只能配置一种,两种可以同时配置,SpringMVC可以根据需要使用不同的映射器查找
    • 不论哪种映射器,都是需要根据url来查找Handler的

非注解的处理器适配器

在非注解情况下我们也可以使用两种适配器,他们有不同的使用场景

  1. <!--配置处理器适配器-->
    <bean id="adapter" class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
    

    使用这种适配器,处理器必须实现Controller接口才行

    此时的处理器:

    public class ItemList01 implements Controller {
        @Override
        public ModelAndView handleRequest(javax.servlet.http.HttpServletRequest httpServletRequest, javax.servlet.http.HttpServletResponse httpServletResponse){
    
            List<Items> list = new ArrayList<>();
            ModelAndView modelAndView = new ModelAndView();
            modelAndView.addObject("itemsList",list);
            modelAndView.setViewName("/WEB-INF/jsp/items/itemsList.jsp");
            return modelAndView;
        }
    }
    

    可以看到,里面只有一个方法,而且最终返回的是ModelAndView对象

  2. <bean class="org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter"/>
    

    使用这种适配器,处理器必须实现HttpRequestHandler接口

    此时的处理器:

    public class ItemList02 implements HttpRequestHandler {
        @Override
        public void handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws ServletException, IOException {
            
        }
    }
    

    可以看到,里面同样只有一个方法,但是返回值为void,这就意味着我们可以使用response来返回json串

  3. 两种方式的比较:

    • 第一种使用起来相对比较简单一点,但是不能返回流
    • 第二种和之前的原始方式很相似,比较麻烦,但是可以通过response返回流
    • 不管是第一种还是第二种都有一个缺陷就是只能写一种方法,不太方便

注解开发中的处理器映射器和处理器适配器

注解中的处理器映射器和处理器适配器需要配对使用

一般使用的是以下两个:

org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter

使用注解配置有两种方式:

  1. <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>
    <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>
    
  2. <mvc:annotation-driven/>
    
  3. 实际开发过程中推荐使用第二种方式进行配置

实际案例

@Controller("itemList")
public class ItemList03 {

    @RequestMapping("/itemsList/queryItems")
    public ModelAndView queryItems(){
        List<Items> list = new ArrayList<>();
        for (int i = 0; i < 3; i++) {
            Items items = new Items();
            items.setPrice((i+1)*120.0f);
            items.setCreatetime(new Date());
            items.setDetail("这是第"+(i+1)+"个作品");
            items.setId(i);
            items.setName("电脑"+i);
            list.add(items);
        }
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.addObject("itemsList",list);
        modelAndView.setViewName("/WEB-INF/jsp/items/itemsList.jsp");
        return modelAndView;
    }
}

其中我们可以使用@RequestMapping注解来替代原来非注解配置url的方式。

配置jsp路径的前缀和后缀

<bean id="resolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix" value="/WEB-INF/jsp/"/>
    <property name="suffix" value=".jsp"/>
</bean>

为视图解析器配置两个参数即可

配置之前

modelAndView.setViewName("/WEB-INF/jsp/items/itemsList.jsp");

配置之后

modelAndView.setViewName("items/itemsList");

@RequestMapping

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

URL映射

在class上添加@RequestMapping(url)指定通用请求前缀, 限制此类下的所有方法请求url必须以请求前缀开头,通过此方法对url进行分类管理。

如下:

@RequestMapping放在类名上边,设置请求前缀 

@Controller
    
@RequestMapping("/item")

方法名上边设置请求映射url:

@RequestMapping放在方法名上边,如下:

@RequestMapping("/queryItem ")

请求方法限定

限定GET方法
@RequestMapping(method = RequestMethod.GET)
//如果通过Post访问则报错:HTTP Status 405 - Request method 'POST' not supported
限定POST方法
@RequestMapping(method = RequestMethod.POST)
GET和POST都可以
@RequestMapping(method={RequestMethod.GET,RequestMethod.POST})

Controller中方法的返回值

ModelAndView

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

public ModelAndView selectByName(){
    ItemsQueryAo query = new ItemsQueryAo();
    Items items = new Items();
    items.setName("电脑");
    query.setItems(items);
    List<ItemsCustom> list = itemsService.getByName(query);
    ModelAndView modelAndView = new ModelAndView();
    modelAndView.addObject("itemsList",list);
    modelAndView.setViewName("items/itemsList");
    return modelAndView;
}

该方式默认使用请求转发

String

public String queryAll(Model model){
        List<ItemsCustom> list = itemsService.getByName(null);
        model.addAttribute("itemsList",list);
        return "items/itemsList";
  }

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

使用该凡是返回的字符串默认使用请求转发的方式解析,同时可以使用加前缀的方式来实现转发和重定向

//重定向
return "redirect:selectAll.action";
//请求转发
return "forward:selectAll.action";

void

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

public void query(HttpServletRequest request, HttpResponse response){

}

参数绑定

处理器适配器在执行Handler之前需要把http请求的key/value数据绑定到Handler方法形参数上。

默认支持的参数类型

  • HttpServletRequest
  • HttpServletResponse
  • HttpSession
  • Model/ModelMap

参数绑定介绍

注解适配器对RequestMapping标记的方法进行适配,对方法中的形参会进行参数绑定,早期springmvc采用PropertyEditor(属性编辑器)进行参数绑定,将request请求的参数绑定到方法形参上,3.X之后springmvc就开始使用Converter进行参数绑定。

简单类型
  • 整型
  • 字符串
  • 浮点数
  • 布尔类型
@RequestParam

使用@RequestParam常用于处理简单类型的绑定。

value:参数名字,即入参的请求参数名字,如value=“item_id”表示请求的参数区中的名字为item_id的参数的值将传入

required:是否必须,默认是true,表示请求中一定要有相应的参数,否则将报;

TTP Status 400 - Required Integer parameter ‘XXXX’ is not present

defaultValue:默认值,表示如果请求中没有同名参数时的默认值

定义如下:

public String editItem(@RequestParam(value="item_id",required=true) String id) {

}

形参名称为id,但是这里使用value=" item_id"限定请求的参数名为item_id,所以页面传递参数的名必须为item_id。

注意:如果请求参数中没有item_id将跑出异常:

HTTP Status 500 - Required Integer parameter ‘item_id’ is not present

这里通过required=true限定item_id参数为必需传递,如果不传递则报400错误,可以使用defaultvalue设置默认值,即使required=true也可以不传item_id参数值

public String query(@RequestParam(value = "id",required = true,defaultValue = "1") Integer id){
    System.out.println(id);
    return "forward:/hello.html";
}
POJO/domain

将pojo对象中的属性名于传递进来的属性名对应,如果传进来的参数名称和对象中的属性名称一致则将参数值设置在pojo对象中

public void query(@RequestParam(value = "id",defaultValue = "1") Integer id,User user){
    user.setId(id);
    System.out.println(user);
}
包装pojo/domain(待定)

所谓包装pojo就是类似于以下方式的对象:

Public class QueryVo {
	private Items items;
}

自定义参数绑定

Converter接口

在实际开发过程中我们可能需要处理各种各样的数据类型,一些简单的数据类型SpringMVC已经帮我们处理好了,但是想Date这种比较复杂的数据类型就需要我们根据需求去自定义转换器,SpringMVC为我们提供了一个接口,我们可以自己去进行实现。

public class DateConverter implements Converter<String, Date> {
    @Override
    public Date convert(String s) {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        try {
            return simpleDateFormat.parse(s);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return null;
    }
}

Converter支持泛型,第一个泛型变量是要转换的参数,第二个是目标参数类型,例如上面就是将String转换为Date类型。

配置自定义的参数绑定
<mvc:annotation-driven conversion-service="conversionService"/>
<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
    <property name="converters">
        <set>
            <ref bean="dateConverter"/>
        </set>
    </property>
</bean>

注意:

<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>
<mvc:annotation-driven conversion-service="conversionService"/>

如果需要进行自定义绑定,那么只需要留下面的配置就可以了,上面的会产生冲突,使配置失效

绑定List类型

需求:

在实际项目开发过程中,可能会需要批量增加或者删除信息,比如说批量删除购物车中的内容,或者学校系统批量增加学生信息。这时候就需要用到List集合来接受参数。

在ItemsQueryAo中添加字段
private List<ItemsCustom> customList;
Controller层设计
@RequestMapping(value = "/testList",method = {RequestMethod.GET,RequestMethod.POST})
public String testList(ItemsQueryAo queryAo){
    //Stream流
    Stream.of(queryAo.getCustomList()).forEach(System.out::println);
    return "items/itemsList";
}
jsp视图层设计
<%这里需要注意,customList是ItemsQueryAo中的字段名称,后面是序号%>
<td><input name="customList[${status.index }].name" value="${item.name }"/></td>

参数绑定总结

  • 内置的参数绑定

    HttpServletRequest、HttpServletResponse、HttpSession、Model

  • 基本类型参数绑定

    int、double/float、String、boolean

  • 简单的pojo/domain

    前端的input中name名称与pojo/domain中的字段相对应即可

  • 复合的pojo/domain

    为了便于程序的拓展与维护,我们往往会使用复合的pojo,复合的pojo中包含简单的pojo,在使用的时候前端页面需要:

    <input type="text" name="itemsCustom.name"/>
    

    pojo:

    private ItemsCustom itemsCustom;
    
  • List类型绑定

数据校验

所需jar包

<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-validator</artifactId>
    <version>6.1.4.Final</version>
</dependency>
<dependency>
    <groupId>org.jboss.logging</groupId>
    <artifactId>jboss-logging</artifactId>
    <version>3.4.1.Final</version>
</dependency>
<dependency>
    <groupId>javax.validation</groupId>
    <artifactId>validation-api</artifactId>
    <version>2.0.1.Final</version>
</dependency>

校验器以及错误信息资源配置

<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
    <property name="providerClass" value="org.hibernate.validator.HibernateValidator"/>
    <property name="validationMessageSource" ref="messageSource"/>
</bean>
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
    <property name="basenames">
        <list>
            <value>classpath:Message</value>
        </list>
    </property>
    <property name="defaultEncoding" value="UTF-8"/>
    <property name="fileEncodings" value="utf-8"/>
    <property name="cacheSeconds" value="120"/>
</bean>

Controller层配置

public void edits(@Validated ItemsCustom itemsCustom,BindingResult bindingResult){
    if (bindingResult.hasErrors()){
        for (ObjectError allError : bindingResult.getAllErrors()) {
            System.out.println(allError.getCode());
        }
    }
}

JavaBean

@Size(min = 2,max = 15,message = "{mvc.items.name.length}")
private String name;

博客参考

https://blog.csdn.net/yangqh521/article/details/81906944

注意

编码问题:

<property name="defaultEncoding" value="UTF-8"/>

不适用于校验JavaBean中复合的JavaBean。

数据回显

在实际开发中我们有时会用到数据回显,所谓的数据回显实际上就是将数据存放到request域中,这样数据就不会丢失,在jsp页面中这种回显数据的方式还是很常用的。主要可以通过三种方式来实现数据回显。

SpringMVC默认支持的数据回显方式

SpringMVC在默认情况下会将pojo数据存入request域中,key等于pojo类型(首字母小写)。

但是在一些情况下,可能jsp页面中使用的并非pojo类型(首字母小写),这时就需要使用一个注解:

@RequestAttribute("itemsCustom")

使用@ModelAttribute注解

该注解用在方法上,作用是将方法的返回值存入到request域中

@ModelAttribute("itemsCustom")
public ItemsCustom getThis(){
    return new ItemsCustom();
}

使用Model对象

@RequestMapping("/sele")
public String toEdits(Model model){
    model.addAttribute("itemsCustom",new ItemsCustom());
    return "items/edit";
}

文件上传及案例

需要导入的jar包:

由于SpringMVC的上传是依赖于fileupload上传组件以及commons-io的,因此需要在pom.xml中添加相应的依赖。

<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.6</version>
</dependency>
<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">
    <property name="maxUploadSize" value="5242880"/>
    <property name="defaultEncoding" value="UTF-8"/>
</bean>

多部件解析器用来解析前端表单的file控件内容,需要在SpringMVC的配置文件中进行相应的配置。

前端

<form action="" method="post" enctype="multipart/form-data">
    <input type="file" name="files">
    <input type="submit" value="提交">
</form>

在表单设计时,我遇到了一个问题:本来只要设计enctype="multipart/form-data"就可以了,但是在使用SpringMVC的过程中,我发现只设计成会报异常,必须指定method=“post”,不知道是什么愿意,记录一下。

后端

 @RequestMapping(value = "/uploading")
    public void upload(@RequestPart(value = "files") MultipartFile files, HttpServletRequest request) throws IOException {
        if (files != null){
            String oldFileName = files.getOriginalFilename();
            if (oldFileName != null && !oldFileName.trim().isEmpty()) {
                String suffix = oldFileName.substring(oldFileName.indexOf("."));
                if (!suffix.trim().isEmpty()) {
                    String newFileName = oldFileName.substring(0, oldFileName.indexOf("."));
                    int index = newFileName.lastIndexOf("//");
                    if (index != -1){
                        newFileName = newFileName.substring(index+1);
                    }
                    String newUUID = UUID.randomUUID().toString().replaceAll("-", "").toUpperCase();
                    String newUUIDFileName = newFileName+newUUID+suffix;
                    String realPath = request.getServletContext().getRealPath("/WEB-INF/files");
                    Date date = new Date();
                    Calendar calendar = Calendar.getInstance();
                    calendar.setTime(date);
                    int year = calendar.get(Calendar.YEAR);
                    int month = calendar.get(Calendar.MONTH);
                    int day = calendar.get(Calendar.DATE);
                    StringBuilder sb = new StringBuilder();
                    String finalFilePath = sb.append(realPath).append("/").append(year).append("/").append(month)
                            .append("/").append(day).append("/").append(newUUIDFileName).toString();
                    File file = new File(finalFilePath);
                    file.mkdirs();
                    files.transferTo(file);
//                    IOUtils.copy(files.getInputStream(),new FileOutputStream(file));
                    //将数据写入数据库
                }else{
                    //输出错误信息,图片格式无法识别
                }
            }else{
                //输出错误信息,请选择图片!
            }
        }

    }

主要就是通过参数绑定:MultipartFile来进行解析。

注意:表单中的name也需要和MulitpartFile的名称相同,也可以通过RequestParam注解来自行指定。

SpringMVC进行json交互

SpringMVC进行json交互主要依赖jackson,所以需要在pom.xml中添加相应的依赖。同时如果没有使用mvc的注解驱动,那么需要自己在控制器适配器中注入相应的依赖。

RequestBody注解

对于前端的设计来说,有的框架会将所有的表单数据封装为json对象,发送给后端,后端收到的是字符串,这是通过这个注解可以自动将前端发来的json串转换为Java对象。如果使用使用key/value的传统方式进行前后端交互,那么就不用使用此注解。

ResponseBody注解

和上面的相对应,该注解将返回值转换为json格式传递给前端解析。

SpringMVC对RESTful的支持

RESTful概述

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

RESTful是一种规范,这种规范在URI路径上体现的比较明显,传统方式下我们传递参数往往通过以下的方式

/items/query.action?a=1&b=2

这种格式使用起来比较复杂,不直观,在使用RESTful规范后可以写成下面的格式

/items/query/1/2

这种方式更为简洁,直观。

SpringMVC使用RESTful规范

SpringMVC配置文件
<mvc:resources mapping="/js/" location="/js/**"/>

使用RESTful规范可能会导致静态资源无法访问,因此我们需要在配置文件中配置静态资源路径进行过滤。

Controller
@RequestMapping("/add/{a}/{b}")
public String add(@PathVariable int a,@PathVariable int b, Model model){
    String result = "结果为:" + a + b;
    model.addAttribute("msg",result);
    return "test";
}
web.xml配置
	<servlet>
        <servlet-name>springMvc</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:springMVC-config.xml</param-value>
        </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>springMvc</servlet-name>
		<!-- <url-pattern>*.action</url-pattern>-->
        <url-pattern>/</url-pattern>
    </servlet-mapping>

上面注释掉的是之前的使用方式,通过后缀配置url,使用RESTful需要按照下方的方式进行配置。

拦截器

拦截器的作用类似于之前的Filter,但是并不是Filter,SpringMVC使用了动态代理对方法进行增强,功能更为强大。

使用SpringMVC的拦截器

实现HandlerInterceptor接口:

public class HandlerInterceptor01 implements HandlerInterceptor {
    /**
     * 该方法是在Controller执行之前进行的,可以用来进行登录校验等工作,返回值为boolean类型,如果返回为true表示可以放行,否则则进行拦截
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
                             Object handler) throws Exception {
        return false;
    }
    /**
     *进入Handler方法之后,返回modelAndView之前执行,可以用来设置一些页面公用的东西,比如路径导航等
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response,
                           Object handler, ModelAndView modelAndView) throws Exception {
    }
    /**
     * 执行Handler完成执行此方法,该方法可以用来进行全局异常处理,也可以记录日志等
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
                                Object handler, Exception ex) throws Exception {
    }
}

在SpringMVC的配置文件中配置拦截器

SpringMVC拦截的是处理器映射器映射的路径即注解中RequestMapping中的路径,在配置过程中,可以配置多个拦截器。

这里有两种配置方式,一种是将自定义的拦截器注入到注解处理器映射器中,一种是配置类似全局拦截器的方式。这里只对第二种进行讲解。

<mvc:interceptors>
    <mvc:interceptor>
        <mvc:mapping path="/**"/>
        <bean class="zzuli.zw.learnSpringMVC.controller.HandlerInterceptor01"/>
    </mvc:interceptor>
</mvc:interceptors>

这里可以配置多个拦截器,而且是顺序执行的。

拦截器应用

需求

进行登录认证,如果是公众网页直接放行,否则重定向到登录界面

Controller
@Controller
public class LoginController {
	// 登陆
	@RequestMapping("/login")
	public String login(HttpSession session, String username, String password)
			throws Exception {

		// 调用service进行用户身份验证
		// ...

		// 在session中保存用户身份信息
		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";
	}
}

拦截器实现
public class LoginInterceptor implements HandlerInterceptor {
	//进入 Handler方法之前执行
	//用于身份认证、身份授权
	//比如身份认证,如果认证通过表示当前用户没有登陆,需要此方法拦截不再向下执行
	@Override
	public boolean preHandle(HttpServletRequest request,
			HttpServletResponse response, Object handler) 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表示拦截,不向下执行
		//return true表示放行
		return false;
	}
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

索半斤_suobanjin

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值