SpringMVC之请求响应\文件上传\异常\拦截器

SpringMVC


概述

SpringMVC是Spring 为展现层提供的基于 MVC 设计理念的优秀的 Web 框架,是目前最主流的 MVC 框架之一。Spring MVC 通过一套 MVC 注解,让 POJO 成为处理请求的控制器,而无须实现任何接口。

支持 restful风格的 URL 请求。采用了松散耦合可插拔组件结构,比其他 MVC 框架更具扩展性和灵活性。


HelloWorld

1、导入jar包或依赖

2、配置 web.xml

配置 DispatcherServlet ,通过 contextConfigLocation 初始化参数自定义配置文件的位置和名称

<servlet>
    <servlet-name>dispatcherServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <!-- 配置 DispatcherServlet 的一个初始化参数: 配置 SpringMVC 配置文件的位置和名称 -->
    <!--
        实际上也可以不通过 contextConfigLocation 来配置 SpringMVC 的配置文件, 而使用默认的.
        默认的配置文件为: /WEB-INF/<servlet-name>-servlet.xml
    -->
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:springmvc.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
    <servlet-name>dispatcherServlet</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

3、创建 Spring MVC 配置文件,配置自动扫描的包和视图解析器(InternalResourceViewResolver)

视图名称解析器:将视图逻辑名解析为: /WEB-INF/pages/<viewName>.jsp

<context:component-scan base-package="com.xingyu"/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix" value="/WEB-INF/views/"/>
    <property name="suffix" value=".jsp"/>
</bean>

4、创建请求处理器类

  • 使用 @RequestMapping 注解来映射请求的 URL
  • 返回值会通过视图解析器解析为实际的物理视图, 对于 InternalResourceViewResolver 视图解析器, 会做如下的解析:
    • 通过 prefix + returnVal + 后缀 这样的方式得到实际的物理视图, 然会做转发操作
    • 即得到实际物理视图为:/WEB-INF/views/success.jsp
@Controller
public class HelloWorld {
    
    
    @RequestMapping("/helloworld")
    public String hello(){
    
    
        System.out.println("你好世界!");
        return "success";
    }
}

@RequestMapping

@RequestMapping 注解为控制器指定可以处理哪些 URL 请求,在控制器的类定义及方法定义处都可标注。

  • 类定义处:提供初步的请求映射信息。相对于 WEB 应用的根目录。
  • 方法处:提供进一步的细分映射信息。相对于类定义处的 URL。若类定义处未标注,则方法处标记的 URL 相对于 WEB 应用的根目录

DispatcherServlet 截获请求后,就通过控制器上 @RequestMapping 提供的映射信息确定请求所对应的处理 方法。

@RequestMapping 除了可以使用请求 URL 映射请求外, 还可以使用请求方法、请求参数及请求头映射请求。@RequestMapping 的 value、method、params 及 heads 分别表示请求 URL、请求方法、请求参数及请求头的映射条件,他们之间是与的关系,联合使用多个条件可让请求映射更加精确化。

params 和 headers支持简单的表达式:

  • param1: 表示请求必须包含名为 param1 的请求参数
  • !param1: 表示请求不能包含名为 param1 的请求参数
  • param1 != value1: 表示请求包含名为 param1 的请求参数,但其值不能为 value1
  • {“param1=value1”, “param2”}: 请求必须包含名为 param1 和param2 的两个请求参数,且 param1 参数的值必须为 value1
@RequestMapping(value = "/hello", method = RequestMethod.GET, params = "userId")

@RequestMapping 还支持 Ant 风格的 URL:

  • /user/*/createUser: 匹配 /user/aaa/createUser、/user/bbb/createUser 等 URL
  • /user/**/createUser: 匹配 /user/createUser、/user/aaa/bbb/createUser 等 URL
  • /user/createUser??: 匹配 /user/createUseraa、/user/createUserbb 等 URL

@PathVariable

带占位符的 URL 是 Spring3.0 新增的功能。通过 @PathVariable 可以将 URL 中占位符参数绑定到控制器处理方法的传入参数中:即URL 中的 {xxx} 占位符可以通过 @PathVariable(“xxx”) 绑定到操作方法的入参中

@RequestMapping("/helloworld/{id}")
public String hello(@PathVariable("id") Integer id){
    
    
    ...
}

REST

REST:即 Representational State Transfer。(资源)表现层状态转化,是目前流行的一种互联网软件架构。

GET、POST、PUT、DELETE。它们分别对应四种基本操作:GET 用来获 取资源,POST 用来新建资源,PUT 用来更新资源,DELETE 用来删除资源。

浏览器 form 表单只支持 GET 与 POST 请求,而DELETE、PUT 等 method 并不支持,Spring3.0 添加了一个过滤器HiddenHttpMethodFilter,可以将这些请求转换 为标准的 http 方法,使得支持 GET、POST、PUT 与 DELETE 请求。


处理请求参数

Spring MVC 通过分析处理方法的签名,将 HTTP 请求信息绑定到处理方法的相应传入参数中,并根据方法的返回值类型做出相应的后续处理。可以对方法及方法入参标注相应的注解( @PathVariable 、@RequestParam、@RequestHeader 等

@RequestParam

在处理方法入参处使用 @RequestParam 可以把请求参数传递给请求方法。

  • value:请求参数的参数名
  • required:请求参数是否必须。默认为 true,表示请求参数中必须包含对应 的参数,若不存在,将抛出异常
  • defaultValue:请求参数的默认值
@RequestMapping("handler2")
public String handler2(@RequestParam("name",required = false)) String username, @RequestParam("password") String password){
    
    
    ...
}

@RequestBody

获取请求体(get请求方式不适用,因为get请求参数在url中,不在请求体)。

得到结果是key=value&key=value&…

@RequestMapping("handler2")
public String handler2(@RequestBody String body){
    
    
    ...
}

@RequestHeader

请求头包含了若干个属性,服务器可据此获知客户端的信 ,通过 @RequestHeader 即可将请求头中的属性值绑定到处理方法的传入参数中。

@RequestMapping("handler3")
public String handler3(@RequestHeader("Accept-Encoding") String ecoding, @RequestHeader("Keep-Alive") long isAlive){
    
    
    ...
}

@CookieValue

@CookieValue 可让处理方法入参绑定某个 Cookie 值

@RequestMapping("handler4")
public String handler4(@CookieValue("JSESSEIONID",required=false) String sessionId, @RequestParam("password") String password){
    
    
    ...
}

POJO 对象绑定

Spring MVC 会按请求参数名和 POJO 属性名进行自动匹配,自动为该对象填充属性值。支持级联属性。 如:dept.deptId、dept.address.tel 等

@RequestMapping("handler5")
public String handler5(User user){
    
    
    ...
}

使用 Servlet API

可以接受如下 ServletAPI 类型的参数:(这种方式会增加程序和servlet相关类的耦合度)

  • HttpServletRequest
  • HttpServletResponse
  • HttpSession
  • java.security.Principal
  • Locale
  • InputStream
  • OutputStream
  • Reader
  • Writer
    @RequestMapping("/testServletAPI")
   public void testServletAPI(HttpServletRequest request,
         HttpServletResponse response, Writer out) throws IOException {
    
    
       System.out.println("testServletAPI, " + request + ", " + response);
       out.write("hello springmvc");
   }

处理模型数据

Spring MVC 提供了以下几种途径输出模型数据:

  • ModelAndView: 处理方法返回值类型为 ModelAndView 时,方法体即可通过该对象添加模型数据
  • Map 及 Model: 入参为 org.springframework.ui.Model、org.springframework.ui. ModelMap 或 java.uti.Map 时,处理方法返回时,Map 中的数据会自动添加到模型中
  • @SessionAttributes: 将模型中的某个属性暂存到 HttpSession 中,以便多个请求之间可以共享这个属性
  • @ModelAttribute: 方法入参标注该注解后, 入参的对象 就会放到数据模型中

ModelAndView

控制器处理方法的返回值如果为 ModelAndView,则其既包含视图信息,也包含模型数据信息

添加模型数据:

  • MoelAndView addObject(String attributeName, Object attributeValue)
  • ModelAndView addAllObject(Map<String, ?> modelMap)

设置视图:

  • void setView(View view)
  • void setViewName(String viewName)
@RequestMapping("/testModelAndView")
public ModelAndView testModelAndView(){
    
    
   String viewName = SUCCESS;
   ModelAndView modelAndView = new ModelAndView(viewName);//viewname是视图名称
   modelAndView.addObject("time", new Date());//加入日期数据
   return modelAndView;
}

Map及Model

Spring MVC 在内部使用了一个 org.springframework.ui.Model 接口存储模型数据。具体步骤:

  • Spring MVC 在调用方法前会创建一个隐含的模型对象作为模型数据的存储容器。
  • 如果方法的入参为 Map 或 Model 类型,Spring MVC 会将隐含模型的引用传递给这些入参。在方法体内,开发者可以通过这个入参对象访问到模型中的所有数据,也可以向模型中添加新的属性数据。
@RequestMapping("/testMap")
public String testMap(Map<String, Object> map){
    
    //传入map的情况,当然也可以传入Model model
   System.out.println(map.getClass().getName()); 
   map.put("names", Arrays.asList("Tom", "Jerry", "Mike"));
   return SUCCESS;
}

@SessionAttributes

若希望在多个请求之间共用某个模型属性数据,则可以在控制器类上标注一个 @SessionAttributes,Spring MVC 将在模型中对应的属性暂存到 HttpSession 中。注意,该注解只能放在类上面,不能放在方法上面。实现了方法间参数共享。

@SessionAttributes 除了可以通过属性名指定需要放到会话中的属性外(value),还可以通过模型属性的对象类型指定哪些模型属性需要放到会话中(type):

  • @SessionAttributes(types=User.class) 会将隐含模型中所有类型 为 User.class 的属性添加到会话中。
  • @SessionAttributes(value={“user1”, “user2”})
  • @SessionAttributes(types={User.class, Dept.class})
  • @SessionAttributes(value={“user1”, “user2”}, types={Dept.class})
@SessionAttributes(value={
    
    "user"}, types={
    
    String.class})//request域和session域中都有
@RequestMapping("/springmvc")
@Controller
public class SpringMVCTest {
    
    
	@RequestMapping("/testSessionAttributes")
	public String testSessionAttributes(Model model){
    
    //保存到session域
        User user = new User("Tom", "123456", "[email protected]", 15);
        model.addAttribute("user", user);
        return SUCCESS;
	}
    
    @RequestMapping("/testGetSessionAttributes")//获取
    public String testGetSessionAttributes(ModelMap modelMap){
    
    
        User user = (User) modelMap.get("user");
        return "success";
    }
    
    @RequestMapping("/testDelSessionAttributes")//删除
    public String testDelSessionAttributes(SessionStatus status){
    
    
        status.setComplete();
        return "success";
    }
}

@ModelAttribute

可以用在方法上或者参数上。

在方法定义上使用 @ModelAttribute 注解:Spring MVC 在调用目标处理方法前,会先逐个调用在方法级上标注了 @ModelAttribute 的方法。

在方法的入参前使用 @ModelAttribute 注解:

  • 可以从隐含对象中获取隐含的模型数据中获取对象,再将请求参数绑定到对象中,再传入入参
  • 将方法入参对象添加到模型中
@ModelAttribute
public void getUser(@RequestParam(value="id",required=false) Integer id, 
      Map<String, Object> map){
    
    
   System.out.println("modelAttribute method");
   if(id != null){
    
    
       //模拟从数据库取出对象
      User user = new User(1, "Tom", "123456", "[email protected]", 12);
      System.out.println(user);
      map.put("user", user);
   }
}

@RequestMapping("/testModelAttribute")
public String testModelAttribute(@ModelAttribute("user") User user){
    
    
    System.out.println(user);
    return SUCCESS;
}

响应

String类型

存入Model对象或者Map对象中,再去JSP中用EL表达式 u s e r . u s e r n a m e 、 {user.username}、 user.username{user.email}获取。

@RequestMapping("/springmvc")
@Controller
public class SpringMVCTest {
    
    
	@RequestMapping("/testSessionAttributes")
	public String testSessionAttributes(Model model){
    
    //保存到session域
        User user = new User("Tom", "123456", "[email protected]", 15);
        model.addAttribute("user", user);
        return "success";
	}
}

void类型

(void类型默认定位到@RequestMapping(“”)所指定目录下的JSP文件。)

方法一:使用Servlet请求转发进行跳转。

@RequestMapping("/springmvc")
@Controller
public class SpringMVCTest {
    
    
	@RequestMapping("/testSessionAttributes")
	public String testSessionAttributes(HttpServletRequest requset, HttpServletResponse response){
    
    
        request.getRequestDispatcher("/WEB-INF/pages/success.jsp").forward(request, response);
        //用HttpServletRequest对象进行请求转发时,SpringMVC不会自动匹配前后缀,需要自己指定。
	}
}

方法二:使用Servlet请求重定向进行跳转。

response.sendRendirct(request.getContextPath()+"/WEB-INF/pages/success.jsp").forward(request, response);//请求重定向不能直接访问WEB-INF下的资源

方法三:直接对浏览器进行响应

response.getWriter().print("hello");

补充:关键字的方式进行转发或者重定向

@RequestMapping("/testForwardOrRedirect")
public String testForwardOrRedirect(){
    
    
    // 请求的转发
    // return "forward:/WEB-INF/pages/success.jsp";

    // 请求的重定向
    return "redirect:/index.jsp";
}

ModelAndView类型

@RequestMapping("/testModelAndView")
public ModelAndView testModelAndView(){
    
    
    // 创建ModelAndView对象
    ModelAndView mv = new ModelAndView();
    // 模拟从数据库中查询出User对象
    User user = new User();
    user.setUsername("小凤");
    user.setPassword("456");
    user.setAge(30);
    // 把user对象存储到mv对象中,也会把user对象存入到request对象
    mv.addObject("user",user);
    // 跳转到哪个页面
    mv.setViewName("success");
    return mv;
}

@ResponseBody响应JSON

使用@ResponseBody注解实现将controller方法返回对象转换为json响应给客户端。(需要引入jackson相关jar包)

@RequestMapping("/testAjax")
public @ResponseBody User testAjax(@RequestBody User user){
    
    
    // 客户端发送ajax的请求,传的是json字符串,后端把json字符串封装到user对象中
    System.out.println(user);
    // 做响应,模拟查询数据库
    user.setUsername("haha");
    user.setAge(40);
    // 做响应
    return user;
}

SpringMVC文件上传

1、跨服务器文件上传:

<dependency>
   <groupId>com.sun.jersey</groupId>
   <artifactId>jersey-client</artifactId>
   <version>1.18.1</version>
</dependency>
<dependency>
    <groupId>com.sun.jersey</groupId>
    <artifactId>jersey-core</artifactId>
    <version>1.18.1</version>
 </dependency>

@RequestMapping("/fileupload3")
public String fileuoload3(MultipartFile upload) throws Exception {
    
    
    String path = "http://localhost:9090/uploads/";
    String filename = upload.getOriginalFilename();
    String uuid = UUID.randomUUID().toString().replace("-", "");
    filename = uuid+"_"+filename;
    
    Client client = Client.create();
    WebResource webResource = client.resource(path + filename);
    webResource.put(upload.getBytes());
    return "success";
}

2、SpringMVC本地文件上传:

 	@RequestMapping("/fileupload2")
    public String fileuoload2(HttpServletRequest request, MultipartFile upload) throws Exception {
    
    
        String path = request.getSession().getServletContext().getRealPath("/uploads/");
        File file = new File(path);
        if(!file.exists()){
    
    
            file.mkdirs();
        }

        String filename = upload.getOriginalFilename();
        String uuid = UUID.randomUUID().toString().replace("-", "");
        filename = uuid+"_"+filename;
        upload.transferTo(new File(path,filename));

        return "success";
    }

SpringMVC异常处理

Controller调用Service,Service调用Dao,异常都是向上抛出,最终由DispatcherServlet找异常处理器进行异常处理。

实现过程:

1、编写自定义异常类(包括提示信息)(extends Exception)

public class SysException extends Exception{
    
    

    // 存储提示信息的
    private String message;
    public String getMessage() {
    
    
        return message;
    }
    public void setMessage(String message) {
    
    
        this.message = message;
    }
    public SysException(String message) {
    
    
        this.message = message;
    }

}

2、编写异常处理器(implements HandlerExceptionResolver)

3、配置异常处理器(跳转到错误页面)

public class SysExceptionResolver implements HandlerExceptionResolver{
    
    
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
    
    
        // 获取到异常对象
        SysException e = null;
        if(ex instanceof SysException){
    
    
            e = (SysException)ex;
        }else{
    
    
            e = new SysException("系统正在维护....");
        }
        // 创建ModelAndView对象
        ModelAndView mv = new ModelAndView();
        mv.addObject("errorMsg",e.getMessage());
        mv.setViewName("error");
        return mv;
    }
}

4、最后在controller、sevice、dao层可能出现异常的方法出都抛出异常

throw new SysException("查询所有用户出现错误了...");

SpringMVC拦截器

过滤器是sevlet规范中的一部分,任何java web工程都可以使用;拦截器是SpringMVC框架自己的,只有使用了SpringMVC框架的工程才可以使用。

过滤器是url-pattern中配置了/*后,可以对所有要访问的资源进行拦截,包括css、js等静态资源;拦截器只会拦截访问的控制器方法(controller),不会拦截静态资源。

自定义拦截器要实现HandlerInterceptor接口。

实现过程:

1、编写拦截器类,实现HandlerInterceptor接口

public class MyInterceptor2 implements HandlerInterceptor{
    
    

    /**
     * 预处理,controller方法执行前
     * return true 放行,执行下一个拦截器,如果没有,执行controller中的方法
     * return false不放行
     */
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    
    
        System.out.println("MyInterceptor1执行了...前2222");
        // request.getRequestDispatcher("/WEB-INF/pages/error.jsp").forward(request,response);
        return true;
    }

    /**
     * 后处理方法,controller方法执行后,success.jsp执行之前
     */
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
    
    
        System.out.println("MyInterceptor1执行了...后2222");
        // request.getRequestDispatcher("/WEB-INF/pages/error.jsp").forward(request,response);
    }

    /**
     * success.jsp页面执行后,该方法会执行
     */
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
    
    
        System.out.println("MyInterceptor1执行了...最后2222");
    }

}

2、配置拦截器,SpringMVC配置文件中进行配置

<!--配置拦截器-->
<mvc:interceptors>
    <!--配置拦截器-->
    <mvc:interceptor>
        <!--要拦截的具体的方法-->
        <mvc:mapping path="/user/*"/>
        <!--不要拦截的方法
        <mvc:exclude-mapping path=""/>
        -->
        <!--配置拦截器对象-->
        <bean class="com.xingyu.interceptor.MyInterceptor1" />
    </mvc:interceptor>

    <!--配置第二个拦截器-->
    <mvc:interceptor>
        <!--要拦截的具体的方法-->
        <mvc:mapping path="/**"/>
        <!--不要拦截的方法
        <mvc:exclude-mapping path=""/>
        -->
        <!--配置拦截器对象-->
        <bean class="com.xingyu.interceptor.MyInterceptor2" />
    </mvc:interceptor>
</mvc:interceptors>

猜你喜欢

转载自blog.csdn.net/qq_40585800/article/details/106728260