文章目录

  • 一、MVC 模式
    • 1.什么是 MVC
    • 2.Servlet
      • MVC 小结
  • 二、Spring MVC
    • 1.Spring MVC 概念
      • 为什么学习 Spring MVC
      • 中央控制器 DispatcherServlet
      • 快速搭建 Spring MVC
    • 2.Spring MVC 原理分析
    • 3.注解开发 Spring MVC
    • 4.Controller 详解
      • 实现接口 Controller
      • 注解 Controller
    • 5.@RequestMapping 说明
    • 6.RestFul 风格
      • 概念
      • 功能
      • 传统操作资源
      • 使用RestFul操作资源
      • 案例演示
      • 小黄鸭调试法
    • 7.转发和重定向
      • 不使用视图解析器
      • 使用视图解析器
    • 8.Spring MVC 处理请求数据
      • 接收前端参数
        • 提交的请求参数名和处理方法的参数名一致
        • 提交的请求参数名和处理方法的参数名不一致
        • 提交一个对象
      • 数据显示到前端
        • 通过ModelAndView
        • 通过Model
        • 通过ModelMap
    • 9.乱码问题
      • 过滤器解决乱码
      • Spring MVC 过滤器
      • 其他情况
    • 10.JSON
      • JSON 简介
        • 概念
        • JSON 键值对
        • JSON 和 JavaScript
      • Controller 返回 JSON 数据
        • Jackson 使用
        • 乱码优化
        • FastJson 使用
  • 三、SSM 整合
      • 项目准备
    • 1.Mybatis 层
    • 2.Spring 层
    • 3.SpringMVC 层
      • 小结
    • 4.编写代码
      • 项目结构
    • 排错思路
  • 四、Ajax
    • 1.Ajax 简介
      • 原生 Ajax
      • jQuery Ajax
    • 2.Spring MVC 实现 jQuery Ajax
      • 案例一,点击事件加载列表
      • 案例二,注册效果提示
  • 五、Spring MVC 拦截器
    • 1.拦截器简介
    • 2.自定义拦截器
    • 3.拦截器案例-验证用户是否登录
  • 六、文件上传和下载
    • 1.简介
      • 对表单中的 enctype 属性做个详细的说明:
    • 2.项目案例

一、MVC 模式

1.什么是 MVC

  • 模型 Model(dao service),视图 View(jsp),控制器 Controller(servlet)
  • 是一种软件设计规范 ,将业务逻辑、数据、显示分离的方法来组织代码
  • MVC主要作用是降低了视图与业务逻辑之间的双向耦合
  • MVC不是一种设计模式,而是一种架构模式,不同的MVC存在差异

Model:模型

  • 数据模型,提供要展示的数据,因此包含数据和行为,可以认为是领域模型或JavaBean组件(包含数据和行为)
  • 现在一般都分离开,即,Value Object (数据层 Dao),服务层(行为 Service)
  • 模型提供了模型数据查询和模型数据的状态更新等功能,包括数据和业务

View:视图

  • 负责进行模型展示,一般就是我们见到的用户界面,客户想看到的东西

Controller :控制器

  • 接收用户请求,交给模型进行处理(状态改变),处理完毕后把返回的模型数据返回给视图,由视图进行展示
  • 控制器相当于调度员

最典型的MVC就是 JSP+Servlet+JavaBean

JSP本质就是个Servlet

2.Servlet

先了解项目结构

创建maven项目,删除父项目src文件夹,创建子模块,添加依赖,

 <dependencies><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>5.1.9.RELEASE</version></dependency><dependency><groupId>javax.servlet.jsp</groupId><artifactId>jsp-api</artifactId><version>2.2</version></dependency><dependency><groupId>javax.servlet</groupId><artifactId>jstl</artifactId><version>1.2</version></dependency></dependencies>

子模块也用普通maven,如果使用maven提供的web项目还需要修改xml,比较麻烦

右键子项目,add framework support 添加框架支持,勾选 web application,create web.xml,选择版本4.0,确认



框架会帮我们创建web项目

添加web依赖,为了防止父项目中没有,我们也可以在子项目中也添加一遍web依赖

 <dependencies><dependency><groupId>javax.servlet</groupId><artifactId>servlet-api</artifactId><version>2.5</version></dependency><dependency><groupId>javax.servlet.jsp</groupId><artifactId>jsp-api</artifactId><version>2.2</version></dependency></dependencies>

创建servlet实现类,重写doGet/doPost方法,用doPost调用doGet方法,实现代码复用

这样我们把业务都写到doGet方法中即可,调用doGet/doPost都正常实现业务

public class MyServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// 获取前端参数String method = req.getParameter("method");if (method.equals("add")) {req.getSession().setAttribute("msg", "执行了add方法");}if (method.equals("delete")) {req.getSession().setAttribute("msg", "执行了delete方法");}// 调用业务层// 视图转发或重定向req.getRequestDispatcher("/WEB-INF/jsp/test.jsp").forward(req, resp);//转发}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {doGet(req, resp);}
}

在WEB-INF中创建一个页面,有安全需求的页面放在WEB-INF目录中,无安全需求的公共资源放在web目录下即可

页面中获取servlet中的响应数据

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>Title</title>
</head>
<body>
${msg}
</body>
</html>

配置 web.xml ,

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"version="4.0"><servlet><servlet-name>MyServlet</servlet-name><servlet-class>com.swy.servlet.MyServlet</servlet-class></servlet><servlet-mapping><servlet-name>MyServlet</servlet-name><url-pattern>hello</url-pattern></servlet-mapping><!-- 额外配置 --><!-- session设置 --><session-config><session-timeout>15</session-timeout></session-config><!-- 首页欢迎页 --><welcome-file-list><welcome-file>index.jsp</welcome-file></welcome-file-list>
</web-app>

准备一个表单页

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>form</title>
</head>
<body><form action="/hello" method="post"><input type="text" name="method"/><input type="submit"/></form>
</body>
</html>

配置tomcat,

选择tomcat local

配置tomcat,首次使用的,还要先准备tomcat,并在这里添加上,点击fix,如果我们的项目创建没问题,就会自动跳转deployment,否则说明项目创建有问题,url表示启动之后自动开启浏览器访问地址

应该自动跳转页面,也可以自己点击deployment,点击+add添加打包,注意下方的application context表示打包路径,改为/,这样我们访问服务器默认首页就是localhost:8080/,否则还要加上一长串的地址,确认,启动服务器

左侧输出的out 目录就是输出的前端项目目录

运行测试,运行后,项目会在我们刚刚配置的路径上(默认根目录)打包,并启动服务

访问测试:

  • localhost:8080
  • http://localhost:8080/hello?method=add
  • http://localhost:8080/hello?method=delete


MVC 小结

MVC框架做了哪些事情:

  • 将url映射到Java类或Java类的方法
  • 封装用户提交的数据
  • 处理请求,调用相关的业务处理,封装响应数据
  • 将相应数据进行渲染,.jsp .html等表示层数据

二、Spring MVC

1.Spring MVC 概念

Spring MVC 是Spring Framework 的一部分,是基于Java实现的MVC的轻量级Web框架(底层还是Servlet)

官方文档:https://docs.spring.io/spring-framework/docs/current/reference/html/web.html

为什么学习 Spring MVC

Spring MVC 特点

  • 轻量级,简单易学
  • 高效,基于请求响应的MVC框架
  • 与 Spring 兼容性好,无缝结合(spring注册的bean,spring mvc都可以用)
  • 约定优于配置(严格遵守约定,不用随意乱改)
  • 功能强大:restful、数据验证、格式化、本地化、主题
  • 简洁灵活
  • 使用的非常广泛

原理图

之前的mvc模式,每一个请求都要有一个servlet来处理请求,非常麻烦

但是,spring 在中间给我们加上了一个调度器,帮助我们统一处理

中央控制器 DispatcherServlet

Spring 的 web 框架围绕 DispatcherServlet 设计,DispatcherServlet 的作用是将请求分发到不同的处理器,从Spring 2.5 开始,使用Java 5 或以上版本的用户可以采取基于注解的controller声明方式,我们也推荐都使用注解开发

DispatcherServlet 的底层还是 Servlet ,只不过帮助我们处理了很多工作,查看源码,通过很多观察常量,可以猜测,底层实现了很多功能

Spring MVC 原理 流程图

快速搭建 Spring MVC

这是一个官方的快速演示项目,所以很多配置很名字都按照官方要求来

创建模块,添加依赖,右键添加web框架,配置web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"version="4.0"><!-- 注册DispatcherServlet --><servlet><servlet-name>springmvc</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><!-- 关联一个springmvc配置文件 --><init-param><param-name>contextConfigLocation</param-name><param-value>classpath:springmvc-servlet.xml</param-value></init-param><!-- 启动级别 --><load-on-startup>1</load-on-startup></servlet><servlet-mapping><servlet-name>springmvc</servlet-name><url-pattern>/</url-pattern></servlet-mapping>
</web-app>

resources目录中添加spring的配置文件,springmvc-servlet.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttps://www.springframework.org/schema/beans/spring-beans.xsd"><!-- 添加处理器映射器 --><bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/><!-- 添加处理器适配器 --><bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/><!-- 视图解析器:DispatcherServlet给ModelAndView添加前后缀 --><bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver"><!-- 前缀 --><property name="prefix" value="/WEB-INF/jsp/"/><!-- 后缀 --><property name="suffix" value=".jsp"/></bean>
</beans>

准备controller,要么使用注解,要么实现Controller接口,返回ModelAndView,封装数据、视图

public class HelloController implements Controller {@Overridepublic ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {// ModelAndView 模型和视图ModelAndView mv = new ModelAndView();// 封装对象,mv.addObject("msg", "HelloSpringMVC");// 封装要跳转的视图mv.setViewName("hello");//名字与hello.jsp对应return mv;}
}

准备视图 hello.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>springmvc</title>
</head>
<body>
${msg}
</body>
</html>

spring的配置文件springmvc-servlet.xml中添加bean

 <!-- Handler --><bean id="/hello" class="com.swy.controller.HelloController"/>

添加tomcat,启动测,可以出现首页

访问 http://localhost:8080/hello

如果出现404,且检查代码无误,排查步骤:

  • 查看控制台输出,是不是少了jar包
  • 如果jar包存在,但页面无法输出,可能是idea发布项目时没有包含lib依赖

进行一下项目设置,

发现项目没有lib,选中WEB-INF文件夹,

在WEB-INF内添加lib文件夹,选中lib,点击+,添加依赖,(别加在文件夹外边,没效果)

添加lib后,可以看到WEB-INF内多了依赖

重新启动tomcat,访问测试:http://localhost:8080/hello

分析:

  • 我们访问的hello.jsp并没有在web.xml中配置,但是可以访问,原因在于spring的配置
  • 处理器和适配器接收请求,然后在spring中找到定的controller处理,
  • controller中有方法处理,返回modeladnview,经过视图解析器,拼接前后缀,
  • 拼接前后缀后,找到对应的jsp文件,返回页面

2.Spring MVC 原理分析


SpringMVC完整流程图

实线部分为SpringMVC框架提供的技术,虚线需要开发者自己实现,以下编号为每一步具体原理

简要流程:

  1. DispatcherServlet表示前端控制器,是整个SpringMVC的控制中心,用户发出请求,DispatcherServlet接收请求并拦截请求
    比如,请求url为,http://localhost:8080/SpringMVC/hello
    那么,http://localhost:8080为服务器域名,SpringMVC为部署在服务器删的web站点,hello为控制器,所以url的含义为
    用户请求位于服务器localhost:8080上的SpringMVC站点上的hello控制器
    这里对应的就是这段代码,因为我们配置的/,所以所有请求都会被拦截

  2. HandlerMapping为处理器映射,来自于DispatcherServle的调用,HandlerMapping根据请求url查找Handler

  3. HandlerException表示具体的Handler,其主要作用是根据url查找控制器,这里查找的控制器为hello
    HandlerException在bean配置中查找到了控制器hello对应了HelloController这个bean

  4. HandlerException将解析后的信息传递给DispatcherServle,如解析控制器映射等,

  5. DispatcherServle调用HandlerAdapter,HandlerAdapter表示处理器适配器,按照特定的规则去执行Handler
    也就是根据处理器hello找对应的HelloController(实现了Controller类的都在查找范围)

  6. Handler让具体的Controller去执行,这里也就是HelloController,HelloController处理后返回ModelAndView,这里实际上还应该继续执行业务,拿到业务层返回的数据再处理,我们给简化了

  7. Controller将具体的执行信息返回给了HandlerAdapter,如ModelAndView

  8. HandlerAdapter将视图逻辑名或模型传递给DispatcherServlet

  9. DispatcherServlet调用视图解析器ViewResolver来解析HandlerAdapter传来的逻辑视图名,ViewResolver做了以下工作
    获取ModelAndView数据,解析ModelAndView中的视图名,视图名就是我们的hello

    拼接视图名前后缀,

  10. 视图解析器HandlerAdapter将解析的视图逻辑名传给 DispatcherServlet,

  11. DispatcherServlet根据视图解析的视图结果,调用具体的视图,这里也就是hello.jsp

  12. 将视图呈现给用户

SpringMVC帮我们做了大量的工作,实际上我们只做了几件事,controller调用业务层,设置视图返回的名字

以上流程看似比较繁琐,其实是为了演示原理,真实开发都会基于注解实现,这才是SpringMVC的精髓

3.注解开发 Spring MVC

演示项目结构

新建模块,添加web application框架支持,添加项目结构lib依赖,

配置web.xml

  • web.xml要求最新版,否则报错(添加框架的方式就是最新版)
  • 注册DisPatcherServlet
  • 关联SpringMVC的配置文件
  • 启动级别1
  • 映射路径/
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"version="4.0"><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-servlet.xml</param-value></init-param><load-on-startup>1</load-on-startup></servlet><servlet-mapping><servlet-name>SpringMVC</servlet-name><url-pattern>/</url-pattern></servlet-mapping>
</web-app>

添加SpringMVC配置文件

  • 开启IOC注解生效
  • 静态资源过滤问题
  • MVC的注解驱动
  • 配置视图解析器
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xmlns:mvc="http://www.springframework.org/schema/mvc"xsi:schemaLocation="http://www.springframework.org/schema/beanshttps://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttps://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/mvchttps://www.springframework.org/schema/mvc/spring-mvc.xsd"><!-- 自动包扫描,让指定包下的注解生效,IOC容器统一管理 --><context:component-scan base-package="com.swy.controller"/><!-- spring mvc不处理静态资源  .css .js .html 等等--><mvc:default-servlet-handler/><!-- 支持mvc注解驱动 --><!-- 在spring中一般采用@RequestMapping注解完成映射关系,要想使@RequestMapping生效,必须向上下文中注册DefaultAnnotationHandlerMappering和一个AnnotationMethodAdapter实例这两个实例分别在类级别和方法级别处理,annotation-driver配置帮我们自动完成上述两个实例的注入--><mvc:annotation-driven/><!-- 视图解析器 --><bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver"><property name="prefix" value="/WEB-INF/jsp/"/><property name="suffix" value=".jsp"/></bean>
</beans>

添加一个jsp文件,注意路径与配置相符

创建controller,添加@Controller,这个类就被spring自动装配,成为一个bean,添加业务方法

这个方法返回的字符串就是我们要展现的视图名字,这个字符串会被视图解析器处理

在方法中添加参数model,model中可以添加一些业务数据,

方法上添加注解@ResquestMapping,注解属性为请求地址,这样这个方法就对应了一个请求url

有多少请求就添加多少方法来映射处理,之前每个请求都需要一个Servlet处理,现在一个请求有一个方法就够了

@ResquestMapping也可以加在controller类上,这样就可以形成多级请求路径

@Controller
@RequestMapping("/springmvc")
public class HelloController {@RequestMapping("/hello")public String hello(Model model) {model.addAttribute("msg","hello kitty");return "hello";}@RequestMapping("/hello")public String hello1(Model model) {model.addAttribute("msg","hello kitty");return "hello";}
}

创建视图层,也就是准备好我们hello.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>hello</title>
</head>
<body>
泥萌好 ${msg}
</body>
</html>

配置tomcat,启动,访问测试:

  • http://localhost:8080/springmvc/hello
  • http://localhost:8080/springmvc/hello1



@Controller也可以改为@RestController,这样这个Controller中的所方法返回的字符串(主要指json格式字符串)就不会被视图解析,供前端页面使用

注意:

  • SpringMVC三大件,处理映射器,处理器适配器,视图解析器,
  • 通常我们只需配置视图解析器即可,另外两个我们只需开启注解即可,springmvc底层实现,省去了大量的xml
  • 请求地址不要重复,否则映射器无法选择

4.Controller 详解

控制器:controller

  • 控制器复杂提供访问程序的行为,通常我们通过接口定义或注解定义两种方法实现
  • 控制器负责解析用户的请求并将其转换为一个模型
  • spring mvc中,一个控制器可以包含多个方法
  • spring mvc中,对于controller的配置方式有很多种

创建准备:

  • 创建模块,
  • 添加web框架,
  • 项目设置添加lib jar包,
  • 配置web.xml中的servlet,
  • 配置spring核心配置文件applicationContext.xml,
  • 准备WEN-INF下的项目目录

实现接口 Controller

Controller是一个接口,在org.springframework.web.servlet.mvc包下,接口只有一个方法,用来处理请求,返回modelandview

实现该接口的类都可以获得控制的功能

public interface Controller {@NullableModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception;
}

写一个controller类

model可以添加数据,跳转页面,

public class ControllerDemo1 implements Controller {@Overridepublic ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {ModelAndView mv = new ModelAndView();mv.addObject("msg", "Controller 接口测试");mv.setViewName("demo1");return mv;}
}

在spring核心配置文件中注册这个bean,注意,bean的name对应请求路径,所以要加上/,class对应处理请求的类

区分:

  • @Component 组件
  • @Service Service层
  • @Controller Controller层
  • @Repository Dao层

这几个注解其实作用都一样,但工作上习惯区分使用

注解 Controller

实现接口Controller的方法,一个请求必须对应一个bean,比较麻烦

使用注解的方法,一个Controller类只需注册一个bean,里面可以通过@RequestMapping+方法处理很多请求

@Controller("/springmvc")
public class ControllerDemo2 {@RequestMapping("/demo1")public String demo1(Model model) {model.addAttribute("msg", "测试demo2");return "demo1";}
}

注意:

  • 无论@Controller和@RequestMapping中怎样添加url,都要确保最终拼接成url的时候刚好被/一个个分隔开,不要多也不要少,否则可能无法正常接收请求
  • 返回的字符串,将会被拼接前后缀,去找对应的jsp页面
  • 实现接口的方式,使用ModelAndView,因为使用ModelAndView主动调用方法才能给字符串去拼接前后缀;
    而注解的方法,我们只需使用Model返回数据(字符串)即可,因为接下来有springmvc去拼接前后缀,不需要我们主动去做的
  • 发布项目时注意tomcat发布的是哪一个项目(模块),发多了影响启动速度,注意启动项目的默认访问根路径,手动设置确认一下;
  • 如果修改了java代码、配置文件,就要重新发布tomcat,如果只修改了前端页面,刷新浏览器即可
  • 视图可以被复用,即,多个控制器可以跳转同一个页面,携带不同的数据而展现不同的效果,因此也可以说,控制器与视图之间是弱耦合关系
  • 返回的字符串也不光只是jsp页面名字,如果类和方法的注解属性拼接的地址还没有达到视图所在文件,那么返回的字符串还要包含剩余的文件路径,也就是确保 类上规定的url+方法上规定的url+字符串(可能包含路径)可以对应到jsp文件,才能通过拼接前后缀正确的找到视图

5.@RequestMapping 说明

@RequestMapping注解作用于映射url到控制器类,或一个特定的处理程序方法,可用于类或方法上,用在类上,表示类中所有的响应请求的方法都是以该地址作为父路径

比如,这个类,所有的请求必须先走/springmvc1,然后在对应各自的方法url

@Controller
@RequestMapping("/springmvc1")
public class ControllerDemo3 {@RequestMapping("/demo3")public String test3(Model model) {model.addAttribute("msg", "controllerTest3");return "demo1";}@RequestMapping("/demo4")public String test4(Model model) {model.addAttribute("msg", "controllerTest4");return "demo1";}
}

6.RestFul 风格

概念

RestFul就是一个资源定位及资源操作的风格,不是标准也不是协议,只是一种风格,基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制

功能

  • 资源:互联网所有的事物都可以被抽象为资源
  • 资源操作:使用 post delete put get 请求类型,使用不同的方法对资源进行操作
  • 分别对应,添加、删除、修改、查询

传统操作资源

通过不同的参数来实现不同的效果,方法比较单一,包括 post和get

  • http://127.0.0.1/item/queryItem.action?id=1 查询 get
  • http://127.0.0.1/item/saveItem.action 新增 post
  • http://127.0.0.1/item/updateItem.action 更新 post
  • http://127.0.0.1/item/deleteItem.action?id=1 删除 get或post

使用RestFul操作资源

可以通过不同的请求方式来实现不用的效果,

  • http://127.0.0.1/item/1 查询 get
  • http://127.0.0.1/item 新增 post
  • http://127.0.0.1/item 更新 put
  • http://127.0.0.1/item/1 删除 delete

查看@RequestMapping源码,可以看到ResuqstMethod属性,进入,可以发现这个属性是个枚举类,里面包含了post/get/put/delete等参数

案例演示

准备controller,添加一个方法

@Controller
public class ControllerDemo4 {@RequestMapping("/add")public String test1(int a, int b, Model model) {int res = a + b;model.addAttribute("msg", "结果为"+res);return "demo1";}
}

普通方式请求:http://localhost:8080/add?a=1&b=2

下面将方法改为RestFul风格,在SpringMVC中,可以使用@PathVariable注解,让方法的参数值对应绑定到一个url模板变量上,比如

 @RequestMapping(value = "/add/{a}/{b}",method = RequestMethod.GET)public String test1(@PathVariable int a, @PathVariable int b, Model model) {int res = a + b;model.addAttribute("msg", "结果为"+res);return "demo1";}

将变量添加注解,同时形参也作为url,需要注意的是url的参数必须按照定义的类型来写,再由method对应get,表示这个方法只接收get请求,浏览器默认请求方式为get方式

访问测试:http://localhost:8080/add/2/3

由于我们定义接收get方法,浏览器又默认使用get方法,所以可以访问,当我们定义method对应其他请求方法时,就会无法访问,这就是为什么同一个访问地址可以对应不同的访问效果,其他请求方式我们可以使用Postman来模拟

当然,上述注解还是比较麻烦,我们进一步简化

 @GetMapping("/add/{a}/{b}")public String test1(@PathVariable int a, @PathVariable int b, Model model) {int res = a + b;model.addAttribute("msg", "结果为"+res);return "demo1";}

这样,这个方法就可以接收,get请求,请求路径为 /add/{a}/{b}

同样,@GetMapping @PostMapping @PutMapping @DeleteMapping 分别对应了 get post put delete请求

因此,同一个请求地址可以通过不同的请求方法来区分对应不同的业务,简化代码

restful风格总结

  • 简介代码,分类归纳,有层次感
  • 更安全,参数写到url模板中,外人也不好判断,哪个是参数
  • 高效,支持缓存
  • 当然也不是最好,因人而异

小黄鸭调试法

我们都有过向别人甚至是不懂程序的人提问,解释编程经历,但是很多时候在我们解释的过程中自己却想到了问题的解决方案,对方却一脸茫然

同行跑来问问题,但是当他自己把问题说完,或者说到一半的时候就想出答案走了

这种现象就是所谓的小黄鸭调试法,他是我们软件工程中最常见的调试方法之一

当自己陷入思维误区时,长时间解决不了问题,如果讲给别人听,为了让别人听懂,自己会站在更清晰、严谨的角度来思考问题,很容易走出自己的思维误区

此概念出自《程序员修炼之道》,传说程序员大师随身携带一只小黄鸭,在调试代码的时候会在桌子上面摆着,然后详细的向鸭子解释每行代码,然后就能很快将问题定位修复

7.转发和重定向

我们虽然在controller层没有见到 HttpServletRequest 和 HttpServletResponse,但是底层Servlet就是用这两个参数进行接收请求和响应结果的,所以我们只需要在controller层的方法参数中添加这两个参数,就可以调出该控制器对应的请求 req 和 res,进而得到所需要的其他参数

 @RequestMapping("/add2/")public String test2(HttpServletRequest request, HttpServletResponse response) {HttpSession session = request.getSession();System.out.println(session.getId());return "demo1";}

访问浏览器,控制台会输出

model是用来添加数据的,不一定非要使用,只要返回jsp页面名字即可,

添加HttpServletRequest 和 HttpServletResponse可以帮助我们获取更多的请求、相应数据,业务中经常使用

不使用视图解析器

我们可以通过SpringMVC来实现转发和重定向,而不使用视图解析器

先将spring配置文件中的视图解析器配置注释掉

这样我们在控制层就不能在返回modelandview,而是返回一个jsp视图的完整路径名,使用的原生方式实现页面跳转

转发可以写成

return "forward:/index.jsp";

重定向写成

return "redirect:/index.jsp";

不写,默认就是转发

return "/index.jsp";

使用视图解析器

取消视图解析配置的注释,开始使用SpringMVC的跳转

直接返回视图名,默认就是转发

return "demo1";

重定向可以写成

return "redirect:/demo1.jsp";

注意,重定向是不能访问WEB-INF中的资源的,如果有需要,还是要使用请求转发

8.Spring MVC 处理请求数据

接收前端参数

提交的请求参数名和处理方法的参数名一致

可以直接接受,比如

 @RequestMapping("/add3")public String test3(String name) {System.out.println(name);return "demo1";}

因此,访问地址:http://localhost:8080/add3?name=swy 可以接收到请求

提交的请求参数名和处理方法的参数名不一致

在方法参数前添加注解,指定将哪个请求参数进行对应

 @RequestMapping("/add4")public String test4(@RequestParam("username") String name) {System.out.println(name);return "demo1";}

对应的访问路径应该是,http://localhost:8080/add4?username=swy

注意:

  • 这里从前端接收参数,不论参数名是否一致,我们推荐都把@RequestParam加上,直观清晰,避免出错

提交一个对象

表单提交我们可以使用单个参数一一接受,也可以使用对象接收

要求请求提交的表单域和对象的属性名必须一致,参数使用对象即可

实体类:

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {private int id;private String name;private int age;
}

控制层

@Controller
@RequestMapping("/user")
public class ControllerDemo5 {@GetMapping("/addUser")public String testUser1(User user) {System.out.println(user);return "demo1";}
}

访问测试:http://localhost:8080/user/addUser?id=1&name=swy&age=18


数据显示到前端

通过ModelAndView

不再赘述

通过Model

不再赘述

通过ModelMap

modelmap继承了哈希链表,可以使用LinkedMap功能,比model更强大,源码可以查看他们之间的关系

使用区别就是:

  • model只有几个方法适用于存储数据,简化了新手对于model的操作和理解
  • modelmap 继承LinkedMap,除了实现自己的一些方法,还可以实现LinkedMap的功能
  • modelandview可以在存储数据的同时,可以进行设置返回的逻辑视图,进行控制展示层的跳转

9.乱码问题

页面上出现乱码,首先打开控制台network,查看response页面的接收数据是否乱码,如果前端接收数据就是乱码,说明时后台Java代码产生的乱码;

出现乱码,可以首先尝试添加HttpServletRequest,使用request.setCharacterEncoding("utf-8")

如果没有效果,可能是接收参数时解析的就是乱码

过滤器解决乱码

创建一个过滤器类,实现Filter接口,注意是servlet包下的,重写方法

public class EncodingFilter implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {}@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {servletRequest.setCharacterEncoding("utf-8");servletResponse.setCharacterEncoding("utf-8");filterChain.doFilter(servletRequest, servletResponse);}@Overridepublic void destroy() {}
}

设置接收请求和发送数据的编码格式,filterChain.doFilter(servletRequest, servletResponse)表示流程继续执行,否则这里会卡死

修改 web.xml,配置过滤器

 <filter><filter-name>encoding</filter-name><filter-class>com.swy.filter.EncodingFilter</filter-class></filter><filter-mapping><filter-name>encoding</filter-name><url-pattern>/</url-pattern></filter-mapping>

/表示拦截所有请求

如果仍然乱码,尝试 切换 请求方式 get/post

Spring MVC 过滤器

上述方式可以尝试,但不够强大,推荐首先使用Spring MVC提供的过滤器

我们先去掉上面的过滤器,添加新的过滤器,

 <!-- 配置Spring MVC的乱码过滤 --><filter><filter-name>encoding</filter-name><filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class><init-param><param-name>encoding</param-name><param-value>utf-8</param-value></init-param></filter><filter-mapping><filter-name>encoding</filter-name><url-pattern>/*</url-pattern></filter-mapping>

/*表示过滤所有请求,这个配置本质上还是filter,但实现的功能十分强大

其他情况

有些极端情况下,这个过滤器对 get 支持不好,所以可以更换 post尝试

tomcat 也可能出现乱码问题,修改tomcat配置

<Connector URIEncoding="utf-8" port="8080" protocol="HTTP/1.1"connectionTimeout="20000"redirectPort="8443" />

也可以自定义过滤器,到网上找一些大佬写好的通用过滤器,复制过来,比Spring MVC还要强大

如果客户端修改了页面编码,导致输入的就是乱码,那么后端不能解决,还是要由前端调整好设置

10.JSON

JSON 简介

前后端分离:

  • 后端部署后端,提供接口,提供数据
  • 前端独立部署,负责渲染后端数据,
  • 前后端通过JSON统一数据交换格式

概念

  • JSON(JavaScript Object Notation)JS对象标记,是一种轻量级的数据交换格式,目前广泛使用
  • 采用完全独立于编程语言的文本格式,来存储和表示数据
  • 易于人阅读和编写,同时也易于机器解析和生成,并有效的提升了网络传输效率

在JavaScript语言中,一切皆对象,因此,任何JavaScript支持的类型都可以通过JSON来表示,如,字符串、数字,对象,数组,等

语法格式:

  • 对象表示为键值对,数据由逗号分隔
  • 花括号保存对象
  • 方括号表示数组

JSON 键值对

用来保存JavaScript对象的一种方式,和JavaScript对象的写法大致相同,键在前,用双引号包裹,值在后,二者分号分隔

比如,

{"name":"swy"}
{"age":"18"}
{"gender":"male"}

JSON 和 JavaScript

如何区分JSON和JavaScript:

  • JSON 就是 JavaScript 对象的字符串表示法,使用文本表示JS对象的信息,本质上还是一个字符串,
  • Java将数据用JSON字符串形式传给前端,JavaScript可以方便的将JSON格式字符串转为Java对象

JavaScript对象,键名也是可以用引号包裹的

var obj = {a:'Hello',b:'world'};

JSON格式字符串,键名必须使用引号包裹

var json = '{"a":"Hello","b":"world"}';

JSON 格式字符串和 JavaScript 对象互转:

  • JSON 转成 JavaScript,使用 JSON.parse() 方法,比如
var obj = JSON.parse('{"a":"Hello","b":"world"}');

结果为{a:'Hello',b:'world'}

  • JavaScript 对象转成 JSON 格式字符串,使用 JSON.stringify() 方法,比如
var json = JSON.stringify({a:'Hello',b:'world'});

结果为 '{"a":"Hello","b":"world"}'

注意:script标签不要写成自闭和,容易出问题,写成双标签

Controller 返回 JSON 数据

Jackson 使用

Jackson 是目前比较好用的 JSON 解析工具

添加依赖,注意,添加依赖后,还要到项目设置中添加lib目录下的jar包

<dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.12.2</version>
</dependency>

再Controller层的方法上添加注解@ResponseBody,

一旦方法添加了@ResponseBody注解,就不会使用视图解析,而是直接返回前端字符串

@Controller
@RequestMapping("/json")
public class ControllerDemo6 {@ResponseBody@RequestMapping("/test1")public String test1() {User user = new User(1, "swy", 18);return user.toString();}
}

访问:http://localhost:8080/json/test1

这是只返回了字符串数据,没有使用视图解析,我们开始进一步,使用 Jackson

使用 Jackson 包中的 ObjectMapper 对象,将对象转为JSON 格式字符串,需要抛出异常

 @ResponseBody@RequestMapping("/test2")public String test2() throws JsonProcessingException {User user = new User(1, "swy", 18);ObjectMapper mapper = new ObjectMapper();return mapper.writeValueAsString(user);}

访问:http://localhost:8080/json/test2

如果出现乱码,可以设置一下编码格式和返回的类型

通过@RequestMapping的produces属性来设置,比如将其改为

@RequestMapping(value = "/test2",produces = "application/json;charset=utf-8")

如果每个方法都添加 @ResponseBody 也比较麻烦,当我们整个controller类中都不使用视图解析的时候,我们可以直接将 @Controller 改为 @RestController ,相当于 @Controller+@ResponseBody,对该类的所有方法有效

ObjectMapper 也可以将时间对象转化字符串,默认返回时间戳,我们可以通过设置,修改返回数据的格式

比如,取消默认返回时间戳,

     ObjectMapper mapper = new ObjectMapper();mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);

以上经常使用的工具,我们也可以统一整理一个工具类,简化代码,提高代码复用性

乱码优化

我们通常不用上述方法,因为比较麻烦,可以使用Spring配置统一指定

修改Spring核心配置文件中的 <mvc:annotation-driven/>标签添加配置

这段代码固定配置,只要使用Jackson,就要添加这段配置,用于处理乱码问题

 <mvc:annotation-driven><mvc:message-converters><bean class="org.springframework.http.converter.StringHttpMessageConverter"><constructor-arg value="UTF-8"/></bean><bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"><property name="objectMapper"><bean class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean"><property name="failOnEmptyBeans" value="false"/></bean></property></bean></mvc:message-converters></mvc:annotation-driven>

FastJson 使用

阿里开发的一款专门用于Java开发的包,可以方便的实现JSON对象与JavaBean对象的转换,实现JavaBean对象与JSON字符串的转换

实现JSON的转换方法很多,最后的实现结果都是一样的

添加pom依赖,然后到项目设置中lib中添加依赖

     <dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.60</version></dependency>

fastjson 中有三个主要的类,

JSONObject 代表 json 对象

  • JSONObject 实现了Map接口,等操作是由Map实现的
  • JSONObject 对应 json 对象,通过各种形式额get方法可以获取到json中,也可以获取键、值对应的个数,判断是否为空,

JSONArray 代表 json 对象数组

  • 底层由List接口中的方法来完成操作的

JSON 代表 JSONObject 和 JSONArray 的转化

  • JSON 类源码分析与使用
  • 总结,这些方法主要是实现 json 对象,json对象数组,javabean 对象,json 字符串之间的转化

三、SSM 整合

项目准备

环境要求

  • IDEA
  • MySQL 5.7.19
  • Tomcat 9
  • Maven 3.6

数据库环境

CREATE DATABASE `ssmbuild`;USE `ssmbuild`;DROP TABLE IF EXISTS `books`;CREATE TABLE `books` (
`bookID` INT(10) NOT NULL AUTO_INCREMENT COMMENT '书id',
`bookName` VARCHAR(100) NOT NULL COMMENT '书名',
`bookCounts` INT(11) NOT NULL COMMENT '数量',
`detail` VARCHAR(200) NOT NULL COMMENT '描述',
KEY `bookID` (`bookID`)
) ENGINE=INNODB DEFAULT CHARSET=utf8INSERT  INTO `books`(`bookID`,`bookName`,`bookCounts`,`detail`)VALUES
(1,'Java',1,'从入门到放弃'),
(2,'MySQL',10,'从删库到跑路'),
(3,'Linux',5,'从进门到进牢');

不要全部执行,一句一句执行

创建 maven 项目,添加依赖,maven资源过滤

junit,数据库驱动,连接池,servlet,jsp,mybatis,mybatis-spring,spring

<dependencies><!--Junit--><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version></dependency><!--数据库驱动--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.47</version></dependency><!-- 数据库连接池 --><dependency><groupId>com.mchange</groupId><artifactId>c3p0</artifactId><version>0.9.5.2</version></dependency><!--Servlet - JSP --><dependency><groupId>javax.servlet</groupId><artifactId>servlet-api</artifactId><version>2.5</version></dependency><dependency><groupId>javax.servlet.jsp</groupId><artifactId>jsp-api</artifactId><version>2.2</version></dependency><dependency><groupId>javax.servlet</groupId><artifactId>jstl</artifactId><version>1.2</version></dependency><!--Mybatis--><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.2</version></dependency><dependency><groupId>org.mybatis</groupId><artifactId>mybatis-spring</artifactId><version>2.0.2</version></dependency><!--Spring--><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>5.1.9.RELEASE</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>5.1.9.RELEASE</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.16.10</version></dependency>
</dependencies>
<build><resources><resource><directory>src/main/java</directory><includes><include>**/*.properties</include><include>**/*.xml</include></includes><filtering>false</filtering></resource><resource><directory>src/main/resources</directory><includes><include>**/*.properties</include><include>**/*.xml</include></includes><filtering>false</filtering></resource></resources>
</build>

创建包结构,controller,dao,pojo,service

resource 添加配置文件,mybatis-config.xml,applicationContext.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration></configuration>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd"></beans>

1.Mybatis 层

resources目录添加数据库配置文件 database.properties,写自己的连接信息

如果mysql版本是8.0+,需要增加时区的配置

useSSL=true的话可能报错,我们选false

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/ssmbuild?useSSL=true&useUnicode=false&characterEncoding=utf8
jdbc.username=root
jdbc.password=123456

编写mybatis核心配置文件,mybatis其他配置交给spring来配置

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration><!-- 开启日志显示 --><settings><setting name="logImpl" value="STDOUT_LOGGING"/></settings><typeAliases><package name="com.swy.pojo"/></typeAliases><mappers><mapper resource="com/swy/dao/BookMapper.xml"/></mappers></configuration>

创建实体类

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Books {private int bookID;private String bookName;private int bookCounts;private String detail;
}

编写Dao层的 Mapper接口

public interface BookMapper {//增加一个Bookint addBook(Books book);//根据id删除一个Bookint deleteBookById(@Param("bookID") int id);//更新Bookint updateBook(Books books);//根据id查询,返回一个BookBooks queryBookById(@Param("bookID") int id);//查询全部Book,返回list集合List<Books> queryAllBook();
}

编写接口对应的 Mapper.xml 文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.swy.dao.BookMapper"><!--增加一个Book--><insert id="addBook" parameterType="Books">insert into ssmbuild.books(bookName,bookCounts,detail)values (#{bookName}, #{bookCounts}, #{detail})</insert><!--根据id删除一个Book--><delete id="deleteBookById" parameterType="int">delete from ssmbuild.books where bookID=#{bookID}</delete><!--更新Book--><update id="updateBook" parameterType="Books">update ssmbuild.booksset bookName = #{bookName},bookCounts = #{bookCounts},detail = #{detail}where bookID = #{bookID}</update><!--根据id查询,返回一个Book--><select id="queryBookById" resultType="Books">select * from ssmbuild.bookswhere bookID = #{bookID}</select><!--查询全部Book--><select id="queryAllBook" resultType="Books">SELECT * from ssmbuild.books</select>
</mapper>

编写Service层的接口和实现类

//BookService:底下需要去实现,调用dao层
public interface BookService {//增加一个Bookint addBook(Books book);//根据id删除一个Bookint deleteBookById(int id);//更新Bookint updateBook(Books books);//根据id查询,返回一个BookBooks queryBookById(int id);//查询全部Book,返回list集合List<Books> queryAllBook();
}

实现类

public class BookServiceImpl implements BookService {//调用dao层的操作,设置一个set接口,方便Spring管理private BookMapper bookMapper;public void setBookMapper(BookMapper bookMapper) {this.bookMapper = bookMapper;}public int addBook(Books book) {return bookMapper.addBook(book);}public int deleteBookById(int id) {return bookMapper.deleteBookById(id);}public int updateBook(Books books) {return bookMapper.updateBook(books);}public Books queryBookById(int id) {return bookMapper.queryBookById(id);}public List<Books> queryAllBook() {return bookMapper.queryAllBook();}
}

2.Spring 层

如查看spring 管理的上下文配置文件,打开项目管理

创建spring配置文件spring-dao.xml,专门处理配置mybatis,整合dao层,作为applicationContext.xml的子文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttps://www.springframework.org/schema/context/spring-context.xsd"><!-- 配置整合mybatis --><!-- 1.关联数据库文件 --><context:property-placeholder location="classpath:database.properties"/><!-- 2.数据库连接池 --><!--数据库连接池dbcp 半自动化操作 不能自动连接c3p0 自动化操作(自动的加载配置文件 并且设置到对象里面)--><bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"><!-- 配置连接池属性 --><property name="driverClass" value="${jdbc.driver}"/><property name="jdbcUrl" value="${jdbc.url}"/><property name="user" value="${jdbc.username}"/><property name="password" value="${jdbc.password}"/><!-- c3p0连接池的私有属性 --><property name="maxPoolSize" value="30"/><property name="minPoolSize" value="10"/><!-- 关闭连接后不自动commit --><property name="autoCommitOnClose" value="false"/><!-- 获取连接超时时间 --><property name="checkoutTimeout" value="10000"/><!-- 当获取连接失败重试次数 --><property name="acquireRetryAttempts" value="2"/></bean><!-- 3.配置SqlSessionFactory对象 --><bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"><!-- 注入数据库连接池 --><property name="dataSource" ref="dataSource"/><!-- 配置MyBaties全局配置文件:mybatis-config.xml --><property name="configLocation" value="classpath:mybatis-config.xml"/></bean><!-- 4.配置扫描Dao接口包,动态实现Dao接口注入到spring容器中 --><!--解释 :https://www.cnblogs.com/jpfss/p/7799806.html--><bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"><!-- 注入sqlSessionFactory --><!-- 只有一个sqlSessionFactory时,不加也行 --><property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/><!-- 给出需要扫描Dao接口包 --><property name="basePackage" value="com.swy.dao"/></bean>
</beans>

Spring整合service层,创建spring-service.xml,

当然,我们也可以通过在service层加注解@Service来解决bean注入的问题,只是这里我们选择了配置文件注入

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd"><!-- 扫描service相关的bean --><context:component-scan base-package="com.swy.service" /><!--BookServiceImpl注入到IOC容器中--><bean id="BookServiceImpl" class="com.swy.service.BookServiceImpl"><property name="bookMapper" ref="bookMapper"/></bean><!-- 配置事务管理器 --><bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><!-- 注入数据库连接池 --><property name="dataSource" ref="dataSource" /></bean>
</beans>

这里的所有spring配置文件都是整合在一块的, 且标签互相引用,我们为了区分层次管理,分多个配置文件处理

3.SpringMVC 层

给项目添加web框架的支持,修改配置文件 web.xml

注意,这里引入的spring配置文件是总的配置,后面我们会创建这个总的配置,用于整合所有spring上下文配置文件

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"version="4.0"><!--DispatcherServlet--><servlet><servlet-name>DispatcherServlet</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><init-param><param-name>contextConfigLocation</param-name><!--一定要注意:我们这里加载的是总的配置文件,之前被这里坑了!--><param-value>classpath:applicationContext.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><!--encodingFilter--><filter><filter-name>encodingFilter</filter-name><filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class><init-param><param-name>encoding</param-name><param-value>utf-8</param-value></init-param></filter><filter-mapping><filter-name>encodingFilter</filter-name><url-pattern>/*</url-pattern></filter-mapping><!--Session过期时间--><session-config><session-timeout>15</session-timeout></session-config>
</web-app>

spring 整合 springmvc 层,创建 spring-mvc.xml 上下文配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xmlns:mvc="http://www.springframework.org/schema/mvc"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/mvchttps://www.springframework.org/schema/mvc/spring-mvc.xsd"><!-- 配置SpringMVC --><!-- 1.开启SpringMVC注解驱动 --><mvc:annotation-driven /><!-- 2.静态资源默认servlet配置--><mvc:default-servlet-handler/><!-- 3.配置jsp 显示ViewResolver视图解析器 --><bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"><property name="viewClass" value="org.springframework.web.servlet.view.JstlView" /><property name="prefix" value="/WEB-INF/jsp/" /><property name="suffix" value=".jsp" /></bean><!-- 4.扫描web相关的bean --><context:component-scan base-package="com.swy.controller" />
</beans>

按照视图解析的配置,在WEB-INF下创建jsp目录

创建spring上下文配置文件,整合所有spring上下文配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd"><import resource="spring-dao.xml"/><import resource="spring-service.xml"/><import resource="spring-mvc.xml"/>
</beans>

小结

web配置,mybatis配置,只保留一小部分内容在原生配置文件中,大部分都写在了spring配置文件中,然后再用一个总的spring配置文件整合所有spring配置,层次清晰,便于管理

如果对每个模块都能熟练掌握,梳理清楚模块与项目之间的关系,更能容易理解这些配置文件的内在关系,

易错:

  • 配置文件内容要结合自己的项目,不要一味复制粘贴
  • 配置文件标签之间存在相互引用,注意命名要统一
  • 标签属性有相似的名字,容易混淆,注意区分
  • 引入文件路径一定要与实际路径向匹配

4.编写代码

添加控制器 BookController,添加第一个方法,查询所有书籍

@Controller
@RequestMapping("/book")
public class BookController {@Autowired@Qualifier("BookServiceImpl")private BookService bookService;@RequestMapping("/allBook")public String list(Model model) {List<Books> list = bookService.queryAllBook();model.addAttribute("list", list);return "allBook";}
}

添加 allBook.jsp 页面

<%--Created by IntelliJ IDEA.User: SuperSongDate: 2021/4/4Time: 11:44To change this template use File | Settings | File Templates.
--%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>书籍列表</title><meta name="viewport" content="width=device-width, initial-scale=1.0"><!-- 引入 Bootstrap --><link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
</head>
<body><div class="container"><div class="row clearfix"><div class="col-md-12 column"><div class="page-header"><h1><small>书籍列表 —— 显示所有书籍</small></h1></div></div></div><div class="row"><div class="col-md-4 column"><a class="btn btn-primary" href="${pageContext.request.contextPath}/book/toAddBook">新增</a></div></div><div class="row clearfix"><div class="col-md-12 column"><table class="table table-hover table-striped"><thead><tr><th>书籍编号</th><th>书籍名字</th><th>书籍数量</th><th>书籍详情</th><th>操作</th></tr></thead><tbody><c:forEach var="book" items="${requestScope.get('list')}"><tr><td>${book.getBookID()}</td><td>${book.getBookName()}</td><td>${book.getBookCounts()}</td><td>${book.getDetail()}</td><td><a href="${pageContext.request.contextPath}/book/toUpdateBook?id=${book.getBookID()}">更改</a> |<a href="${pageContext.request.contextPath}/book/del/${book.getBookID()}">删除</a></td></tr></c:forEach></tbody></table></div></div>
</div>

修改首页 index.jsp 用户跳转页面

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<!DOCTYPE HTML>
<html>
<head><title>首页</title><style type="text/css">a {text-decoration: none;color: black;font-size: 18px;}h3 {width: 180px;height: 38px;margin: 100px auto;text-align: center;line-height: 38px;background: deepskyblue;border-radius: 4px;}</style>
</head>
<body><h3><a href="${pageContext.request.contextPath}/book/allBook">点击进入列表页</a>
</h3>
</body>
</html>

确保添加Tomcat,修改根路径为/,项目设置lib中添加所有依赖

启动 Tomcat 进入首页访问:http://localhost:8080/


BookController 类,添加书籍方法,一个跳转页面,一个添加书籍

@RequestMapping("/toAddBook")
public String toAddPaper() {return "addBook";
}
@RequestMapping("/addBook")
public String addPaper(Books books) {System.out.println(books);bookService.addBook(books);return "redirect:/book/allBook";
}

添加书籍页面:addBook.jsp

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %><html>
<head><title>新增书籍</title><meta name="viewport" content="width=device-width, initial-scale=1.0"><!-- 引入 Bootstrap --><link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="container"><div class="row clearfix"><div class="col-md-12 column"><div class="page-header"><h1><small>新增书籍</small></h1></div></div></div><form action="${pageContext.request.contextPath}/book/addBook" method="post">书籍名称:<input type="text" name="bookName"><br><br><br>书籍数量:<input type="text" name="bookCounts"><br><br><br>书籍详情:<input type="text" name="detail"><br><br><br><input type="submit" value="添加"></form>
</div>

BookController 类, 添加方法,修改书籍,一个方法跳转修改页面,另一个修改书籍信息

@RequestMapping("/toUpdateBook")
public String toUpdateBook(Model model, int id) {Books books = bookService.queryBookById(id);System.out.println(books);model.addAttribute("book",books );return "updateBook";
}
@RequestMapping("/updateBook")
public String updateBook(Model model, Books book) {System.out.println(book);bookService.updateBook(book);Books books = bookService.queryBookById(book.getBookID());model.addAttribute("books", books);return "redirect:/book/allBook";
}

修改书籍页面 updateBook.jsp

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>修改信息</title><meta name="viewport" content="width=device-width, initial-scale=1.0"><!-- 引入 Bootstrap --><link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="container"><div class="row clearfix"><div class="col-md-12 column"><div class="page-header"><h1><small>修改信息</small></h1></div></div></div><form action="${pageContext.request.contextPath}/book/updateBook" method="post"><input type="hidden" name="bookID" value="${book.getBookID()}"/>书籍名称:<input type="text" name="bookName" value="${book.getBookName()}"/>书籍数量:<input type="text" name="bookCounts" value="${book.getBookCounts()}"/>书籍详情:<input type="text" name="detail" value="${book.getDetail() }"/><input type="submit" value="提交"/></form>
</div>

BookController 类, 删除书籍方法

 @RequestMapping("/del/{bookId}")public String deleteBook(@PathVariable("bookId") int id) {bookService.deleteBookById(id);return "redirect:/book/allBook";}

运行Tomcat测试:http://localhost:8080/

项目结构

如果访问失败,查看后面排错思路

排错思路

  1. 查看这个bean是否注入成功 ok
  2. junit单元测试,看代码是否可以查询 ok
  3. 说明底层没有问题,而是spring出问题
  4. spring 整合的时候没有调用到service层的bean
    1.applicationContext.xml 没有注入bean
    2.web.xml中,我们也绑定过配置文件,将其改为总的spring配置文件

一定要看报错,根据错误类型找到对应的模块,深刻理解SSM三大框架的原理,配置文件的作用,才能根据报错准确的定位问题所在

四、Ajax

1.Ajax 简介

什么是Ajax:

  • AJAX = Asynchronous JavaScript and XML(异步的 JavaScript 和 XML)
  • AJAX 是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术
  • Ajax 不是一种新的编程语言,而是一种用于创建更好更快以及交互性更强的Web应用程序的技术
  • 在 2005 年,Google 通过其 Google Suggest 使 AJAX 变得流行起来。Google Suggest能够自动帮你完成搜索单词。
  • Google Suggest 使用 AJAX 创造出动态性极强的 web 界面:当您在谷歌的搜索框输入关键字时,JavaScript 会把这些字符发送到服务器,然后服务器会返回一个搜索建议的列表。就和国内百度的搜索框一样!
  • 传统的网页(即不用ajax技术的网页),想要更新内容或者提交一个表单,都需要重新加载整个网页。
  • 使用ajax技术的网页,通过在后台服务器进行少量的数据交换,就可以实现异步局部更新。
  • 使用Ajax,用户可以创建接近本地桌面应用的直接、高可用、更丰富、更动态的Web用户界面。

利用AJAX可以做:

  • 注册时,输入用户名自动检测用户是否已经存在。
  • 登陆时,提示用户名密码错误
  • 删除数据行时,将行ID发送到后台,后台在数据库中删除,数据库删除成功后,在页面DOM中将数据行也删除
  • 等等

原生 Ajax

<script type="text/javascript">
var xmlhttp;
function loadXMLDoc(url)
{xmlhttp=null;
if (window.XMLHttpRequest){// code for all new browsersxmlhttp=new XMLHttpRequest();}
else if (window.ActiveXObject){// code for IE5 and IE6xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");}
if (xmlhttp!=null){xmlhttp.onreadystatechange=state_Change;xmlhttp.open("GET",url,true);xmlhttp.send(null);}
else{alert("Your browser does not support XMLHTTP.");}
}function state_Change()
{if (xmlhttp.readyState==4){// 4 = "loaded"if (xmlhttp.status==200){// 200 = OK// ...our code here...}else{alert("Problem retrieving XML data");}}
}
</script>

原生代码,仅作为我们理解ajax请求过程,平时不用,我们主要通过jquery来实现

jQuery Ajax

Ajax的核心是XMLHttpRequest对象(XHR)。XHR为向服务器发送请求和解析服务器响应提供了接口。能够以异步方式从服务器获取新数据。

  • jQuery 提供多个与 AJAX 有关的方法。
  • 通过 jQuery AJAX 方法,您能够使用 HTTP Get 和 HTTP Post 从远程服务器上请求文本、HTML、XML 或 JSON – 同时您能够把这些外部数据直接载入网页的被选元素中。
  • jQuery 不是生产者,而是大自然搬运工。
  • jQuery Ajax本质就是 XMLHttpRequest,对他进行了封装,方便调用!

jQuery是一个库,封装了js大量方法,简化代码,我们拿来即用

下载jQuery:https://jquery.com/download/,也可以使用在线CDN

我们使用开发版本,方便查看源码,向项目中导入jquery,放在静态资源目录即可


jQuery Ajax 请求包含参数主要为:

jQuery.ajax(...)部分参数:url:请求地址type:请求方式,GET、POST(1.9.0之后用method)headers:请求头data:要发送的数据contentType:即将发送信息至服务器的内容编码类型(默认: "application/x-www-form-urlencoded; charset=UTF-8")async:是否异步timeout:设置请求超时时间(毫秒)beforeSend:发送请求前执行的函数(全局)complete:完成之后执行的回调函数(全局)success:成功之后执行的回调函数(全局)error:失败之后执行的回调函数(全局)accepts:通过请求头发送给服务器,告诉服务器当前客户端可接受的数据类型dataType:将服务器端返回的数据转换成指定类型"xml": 将服务器端返回的内容转换成xml格式"text": 将服务器端返回的内容转换成普通文本格式"html": 将服务器端返回的内容转换成普通文本格式,在插入DOM中时,如果包含JavaScript标签,则会尝试去执行。"script": 尝试将返回值当作JavaScript去执行,然后再将服务器端返回的内容转换成普通文本格式"json": 将服务器端返回的内容转换成相应的JavaScript对象"jsonp": JSONP 格式使用 JSONP 形式调用函数时,如 "myurl?callback=?" jQuery 将自动替换 ? 为正确的函数名,以执行回调函数

2.Spring MVC 实现 jQuery Ajax

项目准备,创建项目过程不再重复,注意几点:

  • spring配置文件中需要配置静态资源过滤<mvc:default-servlet-handler/>,否则项目启动静态资源无法加载

案例一,点击事件加载列表

添加实体类

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {private String name;private int age;private String gender;
}

添加 controller 层方法,接收请求,返回json格式数据

 @RequestMapping("/test2")public List<User> test2() {List<User> list = new ArrayList<>();list.add(new User("jack", 18, "male"));list.add(new User("mike", 20, "male"));list.add(new User("rose", 24, "female"));return list;}

编写jsp页面,test2.jsp,放在WEB-INF即可,方便访问

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>test2</title><%--<script src="${pageContext.request.contextPath}/statics/js/jquery-3.6.0.js"></script>--%><script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js"></script><script>$(function () {$("#btn").click(function () {$.post("${pageContext.request.contextPath}/ajax/test2",function (data) {console.log(data);var html = "";for (let i=0;i<data.length;i++) {html +="<tr>"+"<td>"+data[i].name+"<td>"+"<td>"+data[i].age+"<td>"+"<td>"+data[i].gender+"<td>"+"<tr>";}$("#content").html(html);});});});</script>
</head>
<body><input type="button" value="异步加载数据" id="btn"><table><tr><td>姓名</td><td>年龄</td><td>性别</td></tr><tbody id="content"></tbody></table>
</body>
</html>


访问:http://localhost:8080/test2.jsp

案例二,注册效果提示

添加controller层方法,用于检测账户、密码,为了简化,我们直接造controller层使用假数据校验参数

@RequestMapping("/checkUser")public String checkUser(String name,String pwd) {String msg = "";//模拟数据库中存在数据if (name!=null){if ("admin".equals(name)){msg = "OK";}else {msg = "用户名输入错误";}}if (pwd!=null){if ("123456".equals(pwd)){msg = "OK";}else {msg = "密码输入有误";}}return msg; //由于@RestController注解,将msg转成json格式返回}

新建登录页面 login.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>checkUser</title><script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js"></script><script>function onblurName(){$.post({url:"${pageContext.request.contextPath}/ajax/checkUser",data:{'name':$("#name").val()},success:function (data) {if (data.toString() =='OK'){$("#userInfo").css("color","green");}else {$("#userInfo").css("color","red");}$("#userInfo").html(data);}});}function onblurPwd(){$.post({url:"${pageContext.request.contextPath}/ajax/checkUser",data:{'pwd':$("#pwd").val()},success:function (data) {if (data.toString() =='OK'){$("#pwdInfo").css("color","green");}else {$("#pwdInfo").css("color","red");}$("#pwdInfo").html(data);}});}</script>
</head>
<body><p>用户名:<input type="text" id="name" onblur="onblurName()"/><span id="userInfo"></span></p><p>密码:<input type="text" id="pwd" onblur="onblurPwd()"/><span id="pwdInfo"></span></p>
</body>
</html>

如果出现乱码,在spring配置文件中添加

 <!-- JSON乱码问题配置 --><mvc:annotation-driven><mvc:message-converters><bean class="org.springframework.http.converter.StringHttpMessageConverter"><constructor-arg value="UTF-8"/></bean><bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"><property name="objectMapper"><bean class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean"><property name="failOnEmptyBeans" value="false"/></bean></property></bean></mvc:message-converters></mvc:annotation-driven>

访问测试:http://localhost:8080/login.jsp

五、Spring MVC 拦截器

1.拦截器简介

SpringMVC的处理器拦截器类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理。开发者可以自己定义一些拦截器来实现特定的功能。

过滤器与拦截器的区别:

  • 拦截器是AOP思想的具体应用。

过滤器

  • servlet规范中的一部分,任何java web工程都可以使用
  • 在url-pattern中配置了/*之后,可以对所有要访问的资源进行拦截

拦截器

  • 拦截器是SpringMVC框架自己的,只有使用了SpringMVC框架的工程才能使用
  • 拦截器只会拦截访问的控制器方法, 如果访问的是jsp/html/css/image/js是不会进行拦截的,减少资源损耗

2.自定义拦截器

如何实现拦截器呢?

想要自定义拦截器,必须实现 HandlerInterceptor 接口。

  1. 新建一个Moudule , springmvc-07-interceptor , 添加web支持
  2. 配置web.xml 和 springmvc-servlet.xml 文件
  3. 编写一个拦截器

web.xml 直接从上一个项目复制

spring配置文件,applicationContext.xml,直接从上一个复制

添加项目设置lib目录依赖

配置Tomcat

确保tomcat启动成功

创建controller层,添加方法测试,

@RestController
public class TestController {@GetMapping("/test1")public String test1() {System.out.println("test1 执行了");return "hello test1";}
}

创建拦截器,MyInterceptor,实现接口HandlerInterceptor,不强制重写方法,根据自己需求重写

通常第一个方法用来拦截,后两个写日志

public class MyInterceptor implements HandlerInterceptor {//在请求处理的方法之前执行//如果返回true执行下一个拦截器//如果返回false就不执行下一个拦截器public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {System.out.println("------------处理前------------");return true;}//在请求处理方法执行之后执行public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {System.out.println("------------处理后------------");}//在dispatcherServlet处理后执行,做清理工作.public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {System.out.println("------------清理------------");}
}

spring上下文配置中添加拦截器配置

 <!--关于拦截器的配置,可以设置多个--><mvc:interceptors><mvc:interceptor><!--/** 包括路径及其子路径--><!--/admin/* 拦截的是/admin/add等等这种 , /admin/add/user不会被拦截--><!--/admin/** 拦截的是/admin/下的所有--><mvc:mapping path="/**"/><!--bean配置的就是拦截器--><bean class="com.swy.config.MyInterceptor"/></mvc:interceptor></mvc:interceptors>

启动Tomcat,访问测试:http://localhost:8080/test1

3.拦截器案例-验证用户是否登录

修改index.jsp作为入口页

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html><head><title>$Title$</title></head><body><h1>首页</h1><hr>
<%--登录--%><a href="${pageContext.request.contextPath}/user/jumplogin">登录</a><a href="${pageContext.request.contextPath}/user/jumpSuccess">成功页面</a></body>
</html>

在jsp目录创建,success.jsp为登录成功页,login.jsp为登录页面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>Title</title>
</head><h1>登录页面</h1>
<hr><body>
<form action="${pageContext.request.contextPath}/user/login">用户名:<input type="text" name="username"> <br>密码:<input type="password" name="pwd"> <br><input type="submit" value="提交">
</form>
</body>
</html>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>Title</title>
</head>
<body><h1>登录成功页面</h1>
<hr>${user}
<a href="${pageContext.request.contextPath}/user/logout">注销</a>
</body>
</html>

控制层添加 LoginConroller,

@Controller
@RequestMapping("/user")
public class LoginController {//跳转到登陆页面@RequestMapping("/jumplogin")public String jumpLogin() throws Exception {return "login";}//跳转到成功页面@RequestMapping("/jumpSuccess")public String jumpSuccess() throws Exception {return "success";}//登陆提交@RequestMapping("/login")public String login(HttpSession session, String username, String pwd) throws Exception {// 向session记录用户身份信息System.out.println("接收前端==="+username);session.setAttribute("user", username);return "success";}//退出登陆@RequestMapping("logout")public String logout(HttpSession session) throws Exception {// session 过期session.invalidate();return "login";}
}

添加登录拦截器

public class LoginInterceptor implements HandlerInterceptor {public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws ServletException, IOException {// 如果是登陆页面则放行System.out.println("uri: " + request.getRequestURI());if (request.getRequestURI().contains("login")) {return true;}HttpSession session = request.getSession();// 如果用户已登陆也放行if(session.getAttribute("user") != null) {return true;}// 用户没有登陆跳转到登陆页面request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request, response);return false;}public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {}public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {}
}

spring配置文件中,注册这个拦截器

 <mvc:interceptor><mvc:mapping path="/**"/><bean id="loginInterceptor" class="com.swy.config.LoginInterceptor"/></mvc:interceptor>

六、文件上传和下载

1.简介

文件上传是项目开发中最常见的功能之一 ,springMVC 可以很好的支持文件上传,但是SpringMVC上下文中默认没有装配MultipartResolver,因此默认情况下其不能处理文件上传工作。如果想使用Spring的文件上传功能,则需要在上下文中配置MultipartResolver。

前端表单要求:为了能上传文件,必须将表单的method设置为POST,并将enctype设置为multipart/form-data。只有在这样的情况下,浏览器才会把用户选择的文件以二进制数据发送给服务器;

对表单中的 enctype 属性做个详细的说明:

  • application/x-www=form-urlencoded:默认方式,只处理表单域中的 value 属性值,采用这种编码方式的表单会将表单域中的值处理成 URL 编码方式。
  • multipart/form-data:这种编码方式会以二进制流的方式来处理表单数据,这种编码方式会把文件域指定文件的内容也封装到请求参数中,不会对字符编码。
  • text/plain:除了把空格转换为 “+” 号外,其他字符都不做编码处理,这种方式适用直接通过表单发送邮件。
<form action="" enctype="multipart/form-data" method="post"><input type="file" name="file"/><input type="submit">
</form>

一旦设置了enctype为multipart/form-data,浏览器即会采用二进制流的方式来处理表单数据,而对于文件上传的处理则涉及在服务器端解析原始的HTTP响应。在2003年,Apache Software Foundation发布了开源的Commons FileUpload组件,其很快成为Servlet/JSP程序员上传文件的最佳选择。

  • Servlet3.0规范已经提供方法来处理文件上传,但这种上传需要在Servlet中完成。
  • 而Spring MVC则提供了更简单的封装。
  • Spring MVC为文件上传提供了直接的支持,这种支持是用即插即用的MultipartResolver实现的。
  • Spring MVC使用Apache Commons FileUpload技术实现了一个MultipartResolver实现类:
  • CommonsMultipartResolver。因此,SpringMVC的文件上传还需要依赖Apache Commons FileUpload的组件。

2.项目案例

添加文件上传相关依赖,

<!--文件上传-->
<dependency><groupId>commons-fileupload</groupId><artifactId>commons-fileupload</artifactId><version>1.3.3</version>
</dependency>
<!--servlet-api导入高版本的-->
<dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>4.0.1</version>
</dependency>

修改首页index.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html><head><title>$Title$</title></head><body><form action="${pageContext.request.contextPath}/upload" enctype="multipart/form-data" method="post"><input type="file" name="file"/><input type="submit"></form></body>
</html>

配置bean:multipartResolver

注意:这个bean的id必须为:multipartResolver , 否则上传文件会报400的错误!

<!--文件上传配置-->
<bean id="multipartResolver"  class="org.springframework.web.multipart.commons.CommonsMultipartResolver"><!-- 请求的编码格式,必须和jSP的pageEncoding属性一致,以便正确读取表单的内容,默认为ISO-8859-1 --><property name="defaultEncoding" value="utf-8"/><!-- 上传文件大小上限,单位为字节(10485760=10M) --><property name="maxUploadSize" value="10485760"/><property name="maxInMemorySize" value="40960"/>
</bean>

添加controller层类,使用CommonsMultipartFile处理上传功能

CommonsMultipartFile 的 常用方法:

  • String getOriginalFilename():获取上传文件的原名
  • InputStream getInputStream():获取文件流
  • void transferTo(File dest):将上传文件保存到一个目录文件中
@Controller
public class FileController {//@RequestParam("file") 将name=file控件得到的文件封装成CommonsMultipartFile 对象//批量上传CommonsMultipartFile则为数组即可@RequestMapping("/upload")public String fileUpload(@RequestParam("file") CommonsMultipartFile file , HttpServletRequest request) throws IOException {//获取文件名 : file.getOriginalFilename();String uploadFileName = file.getOriginalFilename();//如果文件名为空,直接回到首页!if ("".equals(uploadFileName)){return "redirect:/index.jsp";}System.out.println("上传文件名 : "+uploadFileName);//上传路径保存设置String path = request.getServletContext().getRealPath("/upload");//如果路径不存在,创建一个File realPath = new File(path);if (!realPath.exists()){realPath.mkdir();}System.out.println("上传文件保存地址:"+realPath);InputStream is = file.getInputStream(); //文件输入流OutputStream os = new FileOutputStream(new File(realPath,uploadFileName)); //文件输出流//读取写出int len=0;byte[] buffer = new byte[1024];while ((len=is.read(buffer))!=-1){os.write(buffer,0,len);os.flush();}os.close();is.close();return "redirect:/index.jsp";}
}

后续处理。。。

Spring MVC 教程详解 个人总结 复习必备 面试宝典 狂神笔记相关推荐

  1. SpringMVC基础--spring MVC配置详解

    牧涛 --<-<-<@态度决定一切→_→... 博客园 首页 新闻 新随笔 联系 管理 订阅 随笔- 171  文章- 3  评论- 79  spring MVC配置详解 现在主流的 ...

  2. Spring MVC异常处理详解 ExceptionHandler good

    Spring MVC异常处理详解 ExceptionHandler good 参考文章: (1)Spring MVC异常处理详解 ExceptionHandler good (2)https://ww ...

  3. Spring MVC异常处理详解

    Spring MVC异常处理详解 参考文章: (1)Spring MVC异常处理详解 (2)https://www.cnblogs.com/xinzhao/p/4902295.html 备忘一下.

  4. Spring和Spring Mvc整合详解

    Spring和Spring Mvc整合详解 官方主页 Spring Spring Mvc SpringMvc 5,可以参考这一篇<Spring和Spring Mvc 5整合详解> 概述 S ...

  5. spring mvc DispatcherServlet详解之一--request通过HandlerMaping获取控制器Controller过程

    整个spring mvc的架构如下图所示: 现在来讲解DispatcherServletDispatcherServlet的第一步:获取控制器. HandlerMapping HandlerMappi ...

  6. spring mvc DispatcherServlet详解之前传---前端控制器架构

    前端控制器是整个MVC框架中最为核心的一块,它主要用来拦截符合要求的外部请求,并把请求分发到不同的控制器去处理,根据控制器处理后的结果,生成相应的响应发送到客户端.前端控制器既可以使用Filter实现 ...

  7. spring mvc DispatcherServlet详解之三---request通过ModelAndView中获取View实例的过程

    整个spring mvc的架构如下图所示: 上篇文件讲解了DispatcherServlet第二步:通过request从Controller获取ModelAndView.现在来讲解第三步:reques ...

  8. spring mvc DispatcherServlet详解之前传---FrameworkServlet

    做项目时碰到Controller不能使用aop进行拦截,从网上搜索得知:使用spring mvc 启动了两个context:applicationContext 和WebapplicationCont ...

  9. spring mvc DispatcherServlet详解之二---request通过Controller获取ModelAndView过程

    整个spring mvc的架构如下图所示: 上篇文件讲解了DispatcherServlet通过request获取控制器Controller的过程,现在来讲解DispatcherServletDisp ...

最新文章

  1. 逻辑结构图向关系转换规则3
  2. 用WinInet开发Internet客户端应用指南
  3. hadoop如何学习?
  4. 始于《将才》,而不止于将才
  5. 将对象序列化与反序列实例
  6. python回测量化交易策略收益率
  7. oracle aia,[zz] What Are Oracle AIA, PIP and How Do They Work?
  8. 衔接UI线程和管理后台工作线程的类(多线程、异步调用)[转]
  9. 黑客瞄准美国 ATM 机,疯狂窃取超百万美元资金
  10. 完美解决ERROR 1819 (HY000): Your password does not satisfy the current policy requirements
  11. js href的用法
  12. Atitit 图像处理类库大总结attilax qc20
  13. Altium Designer使用--出现的错误报告
  14. RestTemplate 下载文件
  15. ROS launch文档解析
  16. 钉钉桌面版绑定其他邮箱
  17. Scroll View控制菜单栏的伸缩
  18. Coin Change
  19. Unable to load class named
  20. 可视门铃全国产化电子元件推荐方案

热门文章

  1. 【DP专题】——jzoj 6305. 最小值
  2. 小程序实现地图找房功能
  3. Easy Excel读取复杂表格文件
  4. android camera viewport rect,如何判断元素是否在可视区域ViewPort
  5. 计算机管理中无网络适配器,Windows10设备管理器中没有网络适配器如何解决
  6. 超强接口协作平台如何打造:细数Apifox的六把武器
  7. 计算机网络-概述篇(上)
  8. Think Server RD350X 板载RAID设置
  9. three.js学习笔记(四)——Lights灯光
  10. 电子沙盘系统android,交互式军事电子沙盘系统