栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

2021-11-10 Spring MVC

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

2021-11-10 Spring MVC

文章目录
    • MVC架构模式简介
      • 1、MVC是Model、View和Controller的缩写,分别代表 web应用程序中的3种职责。
      • 2、基于servlet的MVC模式
    • SpringMVC简介
      • 1、什么是SpringMVC
      • 2、SpringMVC中重要的组件
      • 3、SpringMVC工作流程
    • SpringMVC的基本使用
      • 1、jar包依赖
      • 2、搭建环境
      • 3、配置前端控制器
      • 4、创建Controller
    • SpringMVC基于注解开发
      • 1、注解介绍
      • 2、搭建环境
      • 3、配置前端控制器
      • 4、创建Controller
      • 5、配置注解驱动
    • 获取请求参数
      • 1、通过HttpServletRequest对象获取请求数据
      • 2、通过参数注入获取请求数据
        • 2.1 注入多参数
          • 2.1.1 不使用注解注入多参数
          • 2.1.2 @RequestParam注解
        • 2.3 注入集合参数
        • 2.4 注入对象参数
          • 2.4.1 注入单个对象
          • 2.4.2 注入关联对象
          • 2.4.3 向List中注入对象
          • 2.4.4 向Map中注入对象
      • 3、字符编码过滤器
        • 3.1 Get请求含有中文乱码解决方案
        • 3.2 Post请求含有中文乱码解决方案
    • 指定处理请求类型
      • 1、@RequestMapping
      • 2、@GetMapping
      • 3、@PostMapping
    • SpringMVC处理响应
      • 1、配置视图解析器
        • 1.1 简单使用
        • 1.2 视图解析器的作用:
      • 2、Spring MVC作用域传值
        • 2.1 Request作用域传值
          • 2.1.1 使用原生的HttpServletRequest
          • 2.1.2 使用Map集合
          • 2.1.3 使用Model接口
        • 2.2 Session作用域传值
        • 2.3 Application作用域传值
      • 3、Spring MVC的响应方式
        • 3.1 请求转发
          • 3.1.1 使用Servlet API
          • 3.1.2 使用forward关键字
          • 3.1.3 使用视图解析器
        • 3.2 重定向
          • 3.2.1 使用Redirect关键字
    • 文件上传与下载
      • 1、文件上传
        • 1.1 搭建环境
        • 1.2 单文件上传
          • 1.2.1 修改项目的访问路径
          • 1.2.2 创建文件上传页面
          • 1.2.3 创建成功页面
          • 1.2.3 创建页面跳转的控制器
          • 1.2.4 创建实现文件上传的控制器
        • 1.3 单文件上传总结
        • 1.4 实现多文件上传
          • 1.4.1 创建多文件上传页面
          • 1.4.2 添加页面跳转方法
          • 1.4.3 创建实现多文件上传的方法
      • 2、文件下载
        • 2.1 添加jstl标签库jar包
        • 2.2 创建下载页面
        • 2.3 添加跳转方法
        • 2.4 添加下载文件的方法
        • 2.5 总结
    • 静态资源映射
      • 1、通过DefaultServlet处理静态资源
      • 2、通过静态资源映射器处理静态资源
      • 3、通过default-servlet-handler处理静态资源
      • 4、对比三种方式
    • SpringMVC的异常处理
      • 1、搭建环境
      • 2、使用@ExceptionHandler注解处理异常
      • 3、使用@ControllerAdvice和@ExceptionHandler处理异常
      • 4、使用SimpleMappingExceptionResolver处理异常
      • 5、自定义HandlerExceptionResolve处理器处理异常
    • SpringMVC拦截器
      • 1、拦截器简介
        • 1.1 什么是拦截器
        • 1.2 执行流程
        • 1.3 拦截器与过滤器的区别
      • 2、定义拦截器
        • 2.1 方法介绍
        • 2.2 拦截器的使用
      • 3、定义全局拦截器
        • 3.1 创建全局拦截器
        • 3.2 在spring-mvc.xml中配置全局拦截器
        • 3.3 说明
    • SpringMVC对Restful风格的支持
      • 1、Restful简介
      • 2、处理 Restful风格的请求
    • JSON数据处理
      • 1、搭建环境
      • 2、处理请求中的JSON格式数据
      • 3、处理响应中的json格式数据
    • SpringMVC解决跨域请求问题
      • 1、什么是同源策略
      • 2、什么是跨域请求
      • 3、通过@CrossOrigin解决跨域
    • SpringMVC常用注解
    • SSM框架整合
      • 1、SSM框架整合介绍
        • 1.1 整合步骤
        • 1.2 jar包依赖
      • 2、搭建环境
        • 2.1 创建表
        • 2.2 创建项目及结构
        • 2.3 配置SSM整合
      • 3、Spring 与 SpringMVC父子容器问题
      • 4、实现用户登录
        • 4.1 用户登录
        • 4.2 记录用户登录日志
    • 基于Maven搭建SSM整合
      • 1、创建Maven项目
      • 2、配置镜像地址
      • 3、添加jar包
      • 4、配置Tomcat插件
      • 5、配置资源拷贝路径
      • 6、配置框架配置文件
      • 7、实现用户查询

MVC架构模式简介 1、MVC是Model、View和Controller的缩写,分别代表 web应用程序中的3种职责。
  • 模型:用于存储数据以及处理用户请求的业务逻辑。
  • 视图:向控制器提交数据,显示模型中的数据。
  • 控制器:根据视图提出的请求判断将请求和数据交给哪个模型处理,将处理后的有关结果交给哪个视图更新显示。
2、基于servlet的MVC模式
  • 模型:一个或多个JavaBean对象,用于存储数据(实体模型,由JavaBean类创建)和处理业务逻辑(业务模型,由一般的Java类创建)。
  • 视图:一个或多个JSP页面,向控制器提交数据和为模型提供数据显示,JSP页面主要使用HTML标记和JavaBean标记来显示数据。
  • 控制器:一个或多个Servlet对象,根据视图提交的请求进行控制,即将请求转发给处理业务逻辑的JavaBean,并将处理结果存放到实体模型JavaBean中,输出给视图显示。

SpringMVC简介 1、什么是SpringMVC

SpringMVC是一个基于MVC模式的Web框架,是Spring框架的一个模块。它以SpringloC容器为基础,并利用容器的特性来简化它的配置,所以SpringMVC和Spring可直接整合使用。SpringMVC对MVC流程进行了封装,屏蔽掉很多底层代码,让开发者可以更加轻松快捷的完成基于MVC模式的Web开发。

2、SpringMVC中重要的组件
  • DispatcherServlet:前端控制器,接受所有请求
  • HandlerMapping:处理器映射器,根据配置的映射规则,找到对应的处理器
  • HandlerAdapter:处理器适配器,执行处理器中处理请求的方法
  • ViewResolver:视图解析器,定位视图。
3、SpringMVC工作流程

工作流程:

  1. 客户端请求提交到DispatcherServlet
  2. 由DispatcherServlet 控制器通过HandlerMapping,找到处理请求的Controller
  3. DispatcherServlet将请求提交到Controller
  4. Controller调用HandlerAdapter执行处理请求的方法
  5. 业务逻辑处理后返回ModelAndView
  6. DispatcherServlet通过ViewResolver视图解析器,找到ModelAndView指定的视图
  7. 视图负责渲染并将结果显示到客户端
SpringMVC的基本使用 1、jar包依赖

Spring核心容器模块

  • spring-beans-5.2.7.RELEASE.jar
  • spring-context-5.2.7.RELEASE.jar
  • spring-core-5.2.7.RELEASE.jar
  • spring-expression-5.2.7.RELEASE.jar

Commons-loggin日志

  • commons-logging-1.2.jar

Spring AOP模块

  • spring-aop-5.2.7.RELEASE.jar

Spring Web模块

  • spring-web-5.2.7.RELEASE.jar

Spring Web MVC模块

  • spring-webmvc-5.2.7.RELEASE.jar

Servlet

  • servlet-api.jar
2、搭建环境

步骤:

  1. 创建web项目

  2. 添加相关jar包

  3. 在src目录下添加springmvc.xml配置文件

    
    
    
    
  4. 添加配置文件中beans的约束文件

3、配置前端控制器

修改web.xml文件




    
    
        springMvc
        org.springframework.web.servlet.DispatcherServlet

        
        
            contextConfigLocation
            classpath:springmvc.xml
        

        
        1
    

    
        springMvc
        
        
        /
    

4、创建Controller

创建Controller,需要实现Controller接口

package com.bjsxt.web.controller;

import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;

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

public class DemoController implements Controller {
    @Override
    public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
        ModelAndView modelAndView = new ModelAndView();
        //响应内容到哪个页面
        modelAndView.setViewName("/index.jsp");
        //响应内容:属性名称和值
        modelAndView.addObject("msg","hello spring mvc");
        return modelAndView;
    }
}

在index.jsp中通过EL表达式获取响应内容

<%@ page contentType="text/html;charset=UTF-8" language="java" %>

    
        $Title$
    
    
        ${msg}
    

在springmvc.xml中配置Controller




    
    

SpringMVC基于注解开发

在SpringMVC的基本使用中我们是以传统方式创建的控制器,它需要实现 Controller接口。传统风格的控制器不仅需要在配置文件中配置映射,而且只能编写一个处理方法,不够灵活。

使用基于注解的控制器具有以下两个优点:

  1. 在基于注解的控制器类中可以编写多个处理方法,进而可以处理多个请求,这就允许将相关的操作编写在同一个控制器类中,从而减少控制器类的数量,方便以后的维护。
  2. 基于注解的控制器不需要在配置文件中部署映射,仅需要使用@RequestMapping 注解就可以将一个URI绑定到类或方法上。
1、注解介绍
  • @Controller Controller注解用于指定Bean对象为控制器

  • @RequesrMapping 用于将一个URI绑定到类上或类的方法中

2、搭建环境

和基本使用中完全相同

3、配置前端控制器

和基本使用中完全相同

4、创建Controller

基于注解创建Controller

package com.bjsxt.web.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

@Controller
@RequestMapping("/con")
public class AnnController {

    
    @RequestMapping("/ann")
    public ModelAndView abc(){
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("/index.jsp");
        modelAndView.addObject("msg","spring mvc ann");
        return modelAndView;
    }
}

在index.jsp中通过EL表达式获取响应内容

修改spring-mvc-ann.xml文件,添加context命名空间,开启注解扫描




    
    

【解决的两个异常】

  1. XML文件错误:web.xml中漏写springmvc配置文件的名称路径
  2. JDK17无法解析某个class文件:换回JDK1.8
5、配置注解驱动

在基于注解方式开发控制器时,需要添加标签,它是启用MVC注解的钥匙。如果没有使用这个标签,而仅仅是使用标签扫描并注册了相关的控制器,那么仅是@Controller @RequestMapping基本功能的注解可以使用除此以外的相关的注解并不能使用。

的作用是提供扩展功能的。

它的处理类AnnotationDrivenBeanDefinitionParser会注册很多基于注解开发时所用到的Bean对象到容器中。其中包含RequestMappingHandlerMapping、RequestMappingHandlerAdapter与ExceptionHandlerExceptionResolver 三个bean。

  1. 在spring-mvc-ann.xml中添加mvc命名空间

    xmlns:mvc="http://www.springframework.org/schema/mvc"
    
    xsi:schemaLocation="...
    http://www.springframework.org/schema/mvc
    http://www.springframework.org/schema/mvc/spring-mvc.xsd"
    
  2. 配置注解驱动

    
    
获取请求参数

在Servlet中我们通过request.getParameter(name)方法获取请求参数。该方式存在两个问题:

  1. 请求参数较多时会出现代码冗余的显现
  2. 与容器紧耦合

在SpringMVC中可以使用HttpServletRequest对象获取请求数据,同时还提供了参数注入的方式用于获取请求数据。

SpringMVC参数注入的优点

  1. 简化参数接收形式(不需要调用任何方法。需要什么参数,就在控制器方法中提供什么参数)
  2. 参数类型不需要自己转换了,如果类型不符会抛出400异常
  3. 可将参数自动封装为对象
  4. 如果没有该参数对应的数据,可为该参数指定默认值
1、通过HttpServletRequest对象获取请求数据
@RequestMapping("/getData")
public ModelAndView getParameter(HttpServletRequest request){
    ModelAndView modelAndView = new ModelAndView();
    String username = request.getParameter("name");
    modelAndView.setViewName("/index.jsp");
    modelAndView.addObject("username",username);
    return modelAndView;
}

在index.jsp中通过EL表达式获取响应内容

2、通过参数注入获取请求数据 2.1 注入多参数 2.1.1 不使用注解注入多参数
@RequestMapping("/addUsers")
public ModelAndView addUsers(String user_name,int user_age){
    ModelAndView modelAndView = new ModelAndView();
    modelAndView.setViewName("/index.jsp");
    modelAndView.addObject("name",user_name);
    modelAndView.addObject("age",user_age);
    return modelAndView;
}

在index.jsp中通过EL表达式获取响应内容

2.1.2 @RequestParam注解

RequestParam:将请求参数绑定到控制器的方法参数上。

  • value:参数名
  • required:是否包含该参数,默认为true,表示该请求路径中必须包含该参数,如果不包含就报错
  • defaultValue:默认参数值,如果设置了该值,required=true将失效,自动为false;如果没有传该参数,就使用默认值
@RequestMapping("/addUsers2")
public ModelAndView addUsers2(@RequestParam(value = "name") String user_name,@RequestParam("age") int user_age){
    ModelAndView modelAndView = new ModelAndView();
    modelAndView.setViewName("/index.jsp");
    modelAndView.addObject("name",user_name);
    modelAndView.addObject("age",user_age);
    return modelAndView;
}
2.3 注入集合参数

在SpringMVC请求参数注入中,如果有多请求参数的name相同,那么可以使用String或List集合来接收请求参数。如果使用的 List类型需要在该参数前添加@RequestParam注解,String[]则不需要。

创建一个addUsers.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>


    Title



    
用户名:
爱好:
体育: 音乐: 艺术:

在Controller类中添加处理请求的方法

@RequestMapping("/addUsers3")
public ModelAndView addUsers3(String username,String[] hobby){
    ModelAndView modelAndView = new ModelAndView();
    modelAndView.setViewName("/index.jsp");
    modelAndView.addObject("name",username);

    String temp = "";
    for(String str:hobby){
        temp += str+" ";
    }
    modelAndView.addObject("hobby",temp);
    return modelAndView;
}

或者

@RequestMapping("/addUsers3")
public ModelAndView addUsers3(String username,@RequestParam(value="hobby") List hobby){
    ModelAndView modelAndView = new ModelAndView();
    modelAndView.setViewName("/index.jsp");
    modelAndView.addObject("name",username);

    String temp = "";
    for(String str:hobby){
        temp += str+" ";
    }
    modelAndView.addObject("hobby",temp);
    return modelAndView;
}

在index.jsp中通过EL表达式获取响应内容

2.4 注入对象参数

在SpringMVc的请求参数注入中,可以使用注入POJO方式来接收请求参数。

要求:请求参数的name必须与POJO的属性名相同。

2.4.1 注入单个对象

创建和表单提交信息相应的pojo类

【注意】表单中单个爱好的属性名是hobby,尽管逻辑上Users类中对应的属性应该是hobbies,但是这么写会报错,必须按照上面的要求:name和属性名一致才行。猜测原因可能是注入对象的方式无法使用@RequestParam指定参数名?

package com.bjsxt.poji;

import java.util.List;

public class Users {
    private String username;
    private List hobby;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public List getHobby() {
        return hobby;
    }

    public void setHobby(List hobby) {
        this.hobby = hobby;
    }
}

在Controller类中添加处理请求的方法

@RequestMapping("/addUsers4")
public ModelAndView addUsers4(Users user){
    ModelAndView modelAndView = new ModelAndView();
    modelAndView.setViewName("/index.jsp");
    modelAndView.addObject("name",user.getUsername());

    String temp = "";
    for(String str: user.getHobby()){
        temp += str+" ";
    }
    modelAndView.addObject("hobby",temp);
    return modelAndView;
}

在index.jsp中通过EL表达式获取响应内容

2.4.2 注入关联对象

SpringMVC可以根据对象的关联关系实现请求参数的注入。

创建一个新的实体类

package com.bjsxt.poji;

public class Address {
    private String phonenumber;
    private String postcode;

    public String getPhonenumber() {
        return phonenumber;
    }

    public void setPhonenumber(String phonenumber) {
        this.phonenumber = phonenumber;
    }

    public String getPostcode() {
        return postcode;
    }

    public void setPostcode(String postcode) {
        this.postcode = postcode;
    }

    @Override
    public String toString() {
        return "Address{" +
                "phonenumber='" + phonenumber + ''' +
                ", postcode='" + postcode + ''' +
                '}';
    }
}

修改Users类,添加address属性,添加get/set方法

package com.bjsxt.poji;

import java.util.List;

public class Users {
    private String username;
    private List hobby;
    private Address address;

    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public List getHobby() {
        return hobby;
    }

    public void setHobby(List hobby) {
        this.hobby = hobby;
    }

    @Override
    public String toString() {
        return "Users{" +
                "username='" + username + ''' +
                ", hobby=" + hobby +
                '}';
    }
}

创建addUsers2.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>


    Title



    
用户名:
爱好:
体育 音乐 艺术
地址:
电话号码: 邮编:

在Controller中添加处理请求的方法

@RequestMapping("/addUsers5")
public ModelAndView addUsers5(Users user){
    ModelAndView modelAndView = new ModelAndView();
    modelAndView.setViewName("/index.jsp");
    modelAndView.addObject("user",user.toString());

    modelAndView.addObject("address",user.getAddress().toString());
    return modelAndView;
}

在index.jsp中通过EL表达式获取响应内容:user 、address

2.4.3 向List中注入对象

在Users类中添加一个泛型为Address的集合类型的属性

private List
addressList; public List
getAddressList() { return addressList; } public void setAddressList(List
addressList) { this.addressList = addressList; }

新建addUsers3.jsp

addressList[0].phonenumber,先集合、再到元素address对象、最后到其属性

<%@ page contentType="text/html;charset=UTF-8" language="java" %>


    Title



    
用户名:
爱好:
体育 音乐 艺术
地址:
电话号码: 邮编:
电话号码: 邮编:

添加处理请求的方法

并没有遍历AddressList集合!是不是可以说会自动跨过集合这层直接读取元素?

@RequestMapping("/addUsers6")
public ModelAndView addUsers6(Users user){
    ModelAndView modelAndView = new ModelAndView();
    modelAndView.setViewName("/index.jsp");
    modelAndView.addObject("user",user.toString());

    modelAndView.addObject("address",user.getAddressList());
    return modelAndView;
}
2.4.4 向Map中注入对象

在Users类中添加一个泛型为Address的Map类型的属性,生成get/set方法

private Map addressMap;

public Map getAddressMap() {
    return addressMap;
}

public void setAddressMap(Map addressMap) {
    this.addressMap = addressMap;
}

新建addUsers4.jsp

addressMap[‘one’].phonenumber,Map的key、key对应的value就是Address对象、再到其属性

<%@ page contentType="text/html;charset=UTF-8" language="java" %>


    Title



    
用户名:
爱好:
体育 音乐 艺术
地址:
电话号码: 邮编:
电话号码: 邮编:

添加处理请求的方法

对于Map,先获取EntrySet对象

@RequestMapping("/addUsers7")
public ModelAndView addUsers7(Users user){
    ModelAndView modelAndView = new ModelAndView();
    modelAndView.setViewName("/index.jsp");
    modelAndView.addObject("user",user.toString());
    Set> set = user.getAddressMap().entrySet();
    modelAndView.addObject("address",set);
    return modelAndView;
}

3、字符编码过滤器

在请求参数中如果含有中文,会出现乱码现象。

3.1 Get请求含有中文乱码解决方案

可通过修改Tomcat的server.xml配置文件,解决中文乱码。


3.2 Post请求含有中文乱码解决方案

org.springframework.web.filter.CharacterEncodingFilter提供了过滤器,不用写,直接配置即可。


    encFilter
    org.springframework.web.filter.CharacterEncodingFilter
    
        encoding
        utf-8
    


    encodeFilter
    
@Controller
@RequestMapping("/page")
public class PageController {

    
    @RequestMapping("/singleFile")
    public String toSingleFile(){
        return "singleFile";
    }

    
    @RequestMapping("/ok")
    public String toOK(){
        return "ok";
    }
}
1.2.4 创建实现文件上传的控制器
package com.bjsxt.web.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.util.UUID;


@Controller
@RequestMapping("/file")
public class FileUploadController {

    @RequestMapping("/singleFile")
    public String singleFileUpload(@RequestParam("file") MultipartFile files, String username, HttpServletRequest request){
        String filename = UUID.randomUUID().toString()+files.getOriginalFilename().substring(files.getOriginalFilename().lastIndexOf("."));
        String realPath = request.getServletContext().getRealPath("/fileUpload");
        File file = new File(realPath,filename);
        try {
            files.transferTo(file);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return "redirect:/page/ok";
    }
}
1.3 单文件上传总结
  • 实现文件上传的表单,提交方式为post,编码格式enctype=multipart/form-data
  • 控制器分离,一个用于实现文件上传,一个用于跳转jsp页面
  • 实现文件上传的控制器中,FileUploadController类和singleFileUpload()方法都映射应当和表单请求的路径对应
  • singleFileUpload()方法中的参数名files,最好和表单中上传文件的input标签中name属性的值一致,否则用@RequestParam指定
  • singleFileUpload()方法的参数MultipartFile files,包含文件名、大小等信息
  • singleFileUpload()方法需要HttpServletRequest对象来获取ServletContext对象,获取绝对路径
  • 为避免文件名相似或重复,使用UUID工具类的randomUUID()方法和subString()方法生成一个不易重复的文件名+扩展名
  • files.transferTo()自动读取和写入文件
  • 成功上传的文件位于 /out/artifacts/fileupload_war_exploded/fileUpload目录,而不是/WEB-INF/fileUpload

过程图示

1.4 实现多文件上传 1.4.1 创建多文件上传页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>


Title



    
用户名:
<%--文件上传name属性的值必须一样--%> 文件上传1:
文件上传2:
1.4.2 添加页面跳转方法
@RequestMapping("/multiFile")
public String toMultiFile(){
    return "multiFile";
}
1.4.3 创建实现多文件上传的方法
@RequestMapping("/multiFile")
public String multiFileUpload(MultipartFile file[],String username, HttpServletRequest request){
    for(MultipartFile temp:file){
        String fileName = UUID.randomUUID().toString()+temp.getOriginalFilename().substring(temp.getOriginalFilename().lastIndexOf("."));
        String realPath = request.getServletContext().getRealPath("/fileUpload");
        File aFile = new File(realPath,fileName);
        try{
            temp.transferTo(aFile);
        }catch(Exception e){
            e.printStackTrace();
        }
    }
    return "redirect:/page/ok";
}

总结

传入multiFileUpload()方法的MultipartFile参数是一个数组,数组中的每个元素就是一个MultipartFile对象。数组的名称和上传文件的input标签name属性的值应当一致。

2、文件下载 2.1 添加jstl标签库jar包
  • jstl.jar
  • standard.jar
2.2 创建下载页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>


    File Download


    <%--item 需要用EL表达式取files--%>
    
        <%--显示文件名,点击请求下载文件--%>
        <%--两条错误代码--%>
        <%--${file}
--%> <%--${file}
--%> ${file}
2.3 添加跳转方法
@RequestMapping("/fileDownload")
public String toFileDownload(Model model, HttpServletRequest request){
    //目标文件所在的文件夹路径
    String realPath = request.getServletContext().getRealPath("/fileUpload");
    File file = new File(realPath);
    
    //获取该文件夹下所有文件的文件名
    String[] arr = file.list();
    model.addAttribute("files",arr);
    return "fileDownload";
}
2.4 添加下载文件的方法
@RequestMapping("/download")
public void fileDownload(String fileName, HttpServletRequest request,HttpServletResponse response){
    //下载文件需要设置的响应头
    response.setHeader("Content-Disposition","attachment;filename="+fileName);

    //从fileupload_war_exploded目录往下找
    //这里提供的是要下载的文件所在的文件夹的路径,无法定位到具体文件,点击会下载一个位置大小的txt文件
    //如果指定具体文件的目录,又无法实现下载文件的可选性
    String realPath = request.getServletContext().getRealPath("/fileUpload");
    File file = new File(realPath,fileName);
    try {
        ServletOutputStream os = response.getOutputStream();
        os.write(FileUtils.readFileToByteArray(file));
        os.flush();
        os.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}
2.5 总结
  • new File(realPath).list()的返回值是包含文件名的String数组
  • 在fileDownload.jsp页面中通过c:forEach标签展示文件名,使用超链接点击请求下载,同时传递要下载文件的文件名
  • 设置响应头response.setHeader("Content-Disposition","attachment;filename="+fileName);
  • 通过路径和文件名定位到文件,将其通过FileUtils读取为为字节数组
  • 获取响应的字节输出流输出到浏览器

过程图示

代码写错出现异常的解决过程:

${file}

写成了

${file}

导致点击下载文件时无法传递fileName,通过浏览器审查发现响应头信息中attachment;filename=为空,有想到可能是fileName没有传递过去,但是看到Tomcat提示信息:getRealPath()方法中的参数/fileUpload是一个目录而不是文件,思考方向就一直固定在目录上,通过尝试:fileUpload、/fileUpload、/fileUpload/、/fileUpload/xxx.jpg四种方式发现只有最后一种方式可行,所以根本原因还是没有定位到要下载的文件,就算这样处理不论点哪个文件都会下载一个固定的文件,显然不合理。最后,终于发现在fileDownload.jsp中传递fileName的超链接的访问地址有问题,原来是将${file}当作字符串拼接了!!!

静态资源映射

当在DispatcherServlet的url-pattern中配置拦截“/”时,除了.jsp不会拦截以外,其他所有的请求都会经过前端控制器进行匹配,此时静态资源,例如 .css、.js、.jpg…就会被前端控制器拦截,导致不能访问,出现404问题。

在web目录下新建image目录,copy一个图片,在WEB-INF/jsp目录下新建一个jsp文件展示该图片,添加一个跳转该页面的方法,测试发现图片无法显示。

原因:web.xml中设置了/,原本直接可以访问的静态资源现在需要通过前端控制器去寻找图片资源,但是如此配置又会拦截图片等静态资源。

1、通过DefaultServlet处理静态资源

F:envrionmentapache-tomcat-9.0.34conf目录下有一个全局的web.xml文件,项目启动时这个全局的配置文件会和项目自身的配置文件合并生效。全局web.xml文件中有一个默认的DefaultServlet,在项目自身的web.xml中,通过对这个DefaultServlet进行配置(无需新建),来放行对静态资源的访问。删除out目录,重启Tomcat测试OK。

缺点:如果静态资源的类型很多,放行配置重复代码很多




    
    
        springMvc
        org.springframework.web.servlet.DispatcherServlet

        
            contextConfigLocation
            classpath:spring-mvc.xml
        
        1
    
    
        springMvc
        /
    

    
    
        default
        
        *.jpg
    

2、通过静态资源映射器处理静态资源

在spring3.0.4以后的SpringMVc模块提供了静态资源映射器组件。通过mvc:resources标签配置静态资源映射器。

修改SpringMVC配置文件

 

创建相关页面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>

    
        Get Users
    
    
        getUsers...
    

<%@ page contentType="text/html;charset=UTF-8" language="java" %>

    
        error1
    
    
        出错了。${msg}
    

<%@ page contentType="text/html;charset=UTF-8" language="java" %>

    
        error2
    
    
        未知异常。${msg}
    

3、使用@ControllerAdvice和@ExceptionHandler处理异常

GlobalExceptionHandler所在的包应当能够被注解扫描。

package com.bjsxt.web.controller;

import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;


@ControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler({java.lang.NullPointerException.class,java.lang.ArithmeticException.class})
    public String nullPointerExceptionHandle(Exception e, Model model){
        model.addAttribute("msg",e);
        return "error1";
    }

    @ExceptionHandler({java.lang.Exception.class})
    public String exceptionHandle(Exception e, Model model){
        model.addAttribute("msg",e);
        return "error2";
    }
}
4、使用SimpleMappingExceptionResolver处理异常

缺点:只能实现跳转,无法传递信息。

【注意】@Configuration @Bean

package com.bjsxt.web.controller;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver;

import java.util.Properties;

@Configuration
public class GlobalExceptionHandler2 {

    @Bean
    public SimpleMappingExceptionResolver getResolver(){
        SimpleMappingExceptionResolver resolver = new SimpleMappingExceptionResolver();
        Properties properties = new Properties();
        properties.setProperty("java.lang.NullPointerException","error1");
        properties.setProperty("java.lang.ArithmeticException","error2");
        resolver.setExceptionMappings(properties);
        return resolver;
    }
}
5、自定义HandlerExceptionResolve处理器处理异常

通过实现HandlerExceptionResolver接口自定义异常处理器,既可以跳转页面,也可以传递信息。

【注意】仍然有@Configuration注解。

package com.bjsxt.web.controller;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;

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


@Configuration
public class GlobalExceptionHandler3 implements HandlerExceptionResolver {

    @Override
    public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {
        ModelAndView modelAndView = new ModelAndView();
        if(e instanceof NullPointerException){
            modelAndView.setViewName("error1");
        }
        if(e instanceof ArithmeticException){
            modelAndView.setViewName("error2");
        }
        modelAndView.addObject("msg",e);
        return modelAndView;
    }
}
SpringMVC拦截器 1、拦截器简介 1.1 什么是拦截器

Spring MVC的拦截器 (Interceptor) 与Servlet的过滤器 (Filter) 类似,它主要用于拦截用户的请求并做相应的处理,通常应用在权限验证、记录请求信息的日志、判断用户是否登录等功能上。

1.2 执行流程

1.3 拦截器与过滤器的区别
  • 拦截器是SpringMVC组件,而过滤器是Servlet 组件
  • 拦截器不依赖容器,过滤器依赖容器
  • 拦截器只能对控制器请求起作用,而过滤器则可以对所有的请求起作用
  • 拦截器可以获取IOC容器中的各个bean,而过滤器就不太方便
2、定义拦截器

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

2.1 方法介绍
  • preHandle()

    该方法在控制器的处理请求方法前执行,其返回值表示是否中断后续操作。返回true表示继续向下执行,返回false表示中断后续操作。

  • postHandle()

    该方法在控制器的处理请求方法执行之后、视图解析之前执行,可以通过此方法对请求域中的模型和视图做进一步的修改。

  • afterCompletion()

    该方法在控制器的处理请求方法执行完成后执行,即视图渲染结束后执行,可以通过此方法实现一些资源清理、记录日志信息等工作。

2.2 拦截器的使用

项目结构图

  1. 创建项目、添加jar包等步骤重复,省略

  2. 创建拦截器,实现HandlerInterceptor接口的MyInterceptor拦截器

    package com.bjsxt.interceptor;
    
    import org.springframework.ui.Model;
    import org.springframework.web.servlet.HandlerInterceptor;
    import org.springframework.web.servlet.ModelAndView;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    
    public class MyInterceptor implements HandlerInterceptor {
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            System.out.println("preHandle...处理请求方法前");
            return true;
        }
    
        @Override
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
            System.out.println("postHandle...处理请求方法执行之后、视图解析之前");
        }
    
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
            System.out.println("afterCompletion...处理请求方法执行完成后");
        }
    }
    
  3. 在spring-mvc.xml中配置拦截器

    
        
            
             
    

    创建自定义异常

    package com.bjsxt.exception;
    
    public class UserNotFoundException extends RuntimeException{
        public UserNotFoundException() {
            super();
        }
    
        public UserNotFoundException(String message) {
            super(message);
        }
    
        public UserNotFoundException(String message, Throwable cause) {
            super(message, cause);
        }
    }
    

    创建用户登录控制器

    package com.bjsxt.web.controller;
    
    import com.bjsxt.pojo.Users;
    import com.bjsxt.service.UsersService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    
    import javax.servlet.http.HttpSession;
    
    
    @Controller
    @RequestMapping("/user")
    public class UsersController {
    
        @Autowired
        private UsersService usersService;
    
        
        public String userLogin(Users users, HttpSession session){
            Users user = this.usersService.userLogin(users);
            session.setAttribute("user",user);
            return "redirect:/page/index";
        }
    }
    

    全局异常处理器

    package com.bjsxt.web.controller;
    
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.ControllerAdvice;
    import org.springframework.web.bind.annotation.ExceptionHandler;
    
    
    @ControllerAdvice
    public class GlobalExceptionController {
        @ExceptionHandler({com.bjsxt.exception.UserNotFoundException.class})
        public String userNotFoundExceptionHandle(Exception e, Model model){
            model.addAttribute("msg",e.getMessage());
            return "login";
        }
    
        @ExceptionHandler({java.lang.Exception.class})
        public String exceptionHandle(Exception e){
            return "redirect:/page/error";
        }
    
    }
    

    创建用户登录页面

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    
    
        Title
    
    
        ${msg}
        
    用户名:
    密码:

    创建异常提示页面

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    
    
        Error
    
    
        出错了,请与管理员联系。
        email:1615669687@qq.com
    
    
    

    创建页面跳转控制器

    package com.bjsxt.web.controller;
    
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RequestMapping;
    
    
    @Controller
    public class PageController {
    
        @RequestMapping("/")
        public String showIndex(){
            return "index";
        }
    
        
        @RequestMapping("/page/{page}")
        public String showPage(@PathVariable String page){
            return page;
        }
    }
    

    创建拦截器——判断用户是否登录

    package com.bjsxt.interceptor;
    
    import com.bjsxt.pojo.Users;
    import org.springframework.web.servlet.HandlerInterceptor;
    import org.springframework.web.servlet.ModelAndView;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import javax.servlet.http.HttpSession;
    
    public class LoginInterceptor implements HandlerInterceptor {
    
        
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            HttpSession session = request.getSession();
            Users user = (Users)session.getAttribute("user");
    
            if(user == null || user.getUsername().length() <= 0){
                response.sendRedirect("/page/login");
                return false;
            }
            return true;
        }
    }
    

    配置拦截器

    
        
             
  4. 创建Users扩展实体类

    package com.bjsxt.pojo;
    
    public class UsersExt extends Users{
        private String ip;
    
        public String getIp() {
            return ip;
        }
    
        public void setIp(String ip) {
            this.ip = ip;
        }
    }
    
  5. 修改控制器

    package com.bjsxt.web.controller;
    
    import com.bjsxt.pojo.Users;
    import com.bjsxt.pojo.UsersExt;
    import com.bjsxt.service.UsersService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.http.HttpRequest;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpSession;
    
    
    @Controller
    @RequestMapping("/user")
    public class UsersController {
    
        @Autowired
        private UsersService usersService;
    
        
        @RequestMapping("/userLogin")
        public String userLogin(UsersExt users, HttpSession session, HttpServletRequest request){
            String ip = request.getRemoteAddr();
            users.setIp(ip);
            Users user = this.usersService.userLogin(users);
            session.setAttribute("user",user);
            // return "index";
            //关于为什么这里必须是重定向,且redirect:/page/index
            return "redirect:/page/index";
    
        }
    }
    
  6. 配置切面

    • 在applicationContext-service.xml中开启aop包注解扫描

      
      
    • 在applicationContext-trans.xml中开启aspecyJ自动代理和登录操作的事务管理

      
      
      
          
          
              
          
      
          
          
              
                  
                  
                  
                  
                  
                  
              
          
      
          
          
              
              
          
      
          
      
      

【一个异常】提示找不到Logs LogsMapper类

原因:对于aop包,不应在spring-mvc.xml中扫描注解。

基于Maven搭建SSM整合

使用Spring两个问题:

  • jar包管理不易
  • 配置文件管理不易

Maven能够很好的解决jar包管理的问题,通过给定坐标,自动导入jar包依赖。

1、创建Maven项目

将普通的jar项目改造为war项目

  1. 创建目录和相关文件

    src—>main—>webapp—>WEB-INF—>web.xml

  2. 在pom.xml文件中添加

    com.bjsxt
    maven_ssm_demo
    1.0-SNAPSHOT
    
    
    war
    
  3. 如果webapp目录不能直接新建jsp文件,在项目结构中通过modules添加web组件

2、配置镜像地址

Maven中央仓库是国外站点,下载构件较慢,可配置国内的阿里镜像或其他镜像地址。配置镜像地址时需要Maven的settings.xml配置文件。该配置文件需要从Apache下载的Maven中获取。最后在ldea中指定该配置文件路径。

3、添加jar包

Maven通过坐标管理jar包或插件。在中央仓库查找依赖构件的坐标,并将该坐标添加到Maven的pom.xml文件中。

Maven查找构件的顺序:先从本地仓库中查找,如果本地仓库没有则会去中央仓库下载并保存到本地仓库中。

中央仓库地址:

https://mvnrepository.com/

本地仓库默认路径为:

C:Users86150.m2repository

可以在settings.xml文件中指定本地仓库的路径

F:.m2repository

也可以在ldea中指定Maven的设置文件和本地仓库路径

3.1 配置依赖jar包的坐标


    
    
        org.mybatis
        mybatis
        3.5.7
    

    
    
        org.mybatis
        mybatis-spring
        2.0.6
    

    
    
        org.aspectj
        aspectjweaver
        1.9.6
        runtime
    

    
    
        org.springframework
        spring-aspects
        5.3.12
    

    
    
        org.springframework
        spring-webmvc
        5.3.12
    

    
    
        org.springframework
        spring-jdbc
        5.3.12
    

    
    
        javax.servlet
        javax.servlet-api
        4.0.1
        provided
    

    
    
        javax.servlet
        jstl
        1.2
    

    
    
        mysql
        mysql-connector-java
        5.1.48
    

4、配置Tomcat插件 5、配置资源拷贝路径

    
        
        
            org.apache.tomcat.maven
            tomcat7-maven-plugin
            2.2
            
                
                8080
                
                /
            
        
    
    
    
        
            src/main/java
            
                ***.xml
                **/*.properties
            
        
    

配置Tomcat插件显示异常

Cannot resolve plugin org.apache.tomcat.maven:tomcat7-maven-plugin

【解决】使用version标签添加版本号

为什么要配置资源拷贝路径?

【原因】Maven默认从resources目录加载配置文件,但UsersMapper.xml、UsersMapper.java等映射配置文件位于com.bjsxt.mapper包下,为了加载全部的配置文件,配置java和resources两个资源拷贝目录。

启动Tomcat插件直接报错,process terminated,意思是本地仓库都默认路径拒绝Maven访问

【解决】将repository目录和settings.xml文件复制到F盘,在IDEA中重新指定路径。

6、配置框架配置文件

UsersMapper.java、UsersMapper.java等放在mapper包中,其他的.properties文件、.xml文件放在resources目录中。

7、实现用户查询
  1. 创建查询用户到控制器

    package com.bjsxt.web.controller;
    
    import com.bjsxt.pojo.Users;
    import com.bjsxt.service.UsersService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.RequestMapping;
    
    import java.util.List;
    
    @Controller
    @RequestMapping("/user")
    public class UsersController {
    
        @Autowired
        private UsersService usersService;
    
        @RequestMapping("/findUsers")
        public String findUsersAll(Model model){
            List list = this.usersService.findUsersAll();
            model.addAttribute("list",list);
            return "showUsers";
        }
    }
    
  2. 创建展示用户信息的页面

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
    
    
        show users
    
    
        
            <%--注意这里的list也要使用EL表达式取--%>
            
                
    用户ID 用户名 密码
    ${user.userid} ${user.username} ${user.userpwd}
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/462000.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号