SpringMVC
1. 什么是SpringMVC
1.1 定义
Spring MVC是Spring Framework的一部分,是基于Java实现MVC的轻量级Web框架。
1.2 特点
- 轻量级,简单易学
- 高效,基于请求响应的MVC框架
- 与Spring兼容性好,无缝贴合
- 约定优于配置
- 功能强大:Restful、数据验证、格式化、本地化、主题等
- 简洁灵活
1.3 中心控制器
- Spring的web框架围绕DispatcherServlet设计。DispatcherServlet的作用是将请求分发到不同的处理器。从Spring 2.5开始,使用Java 5或者以上版本的用户可以采用基于注解的controller声明方式。
- Spring MVC框架像许多其他MVC框架一样,以请求为驱动,围绕一个中心Servlet分派请求及提供其他功能,DispatcherServlet是一个实际的Servlet(它继承自HttpServlet基类)。
2. 原理
- 当用户发起请求时,被前置的控制器拦截到请求
- 前端控制器根据请求参数生成代理请求,找到请求的对应的实际控制器
- 控制器处理请求,创建数据模型,访问数据库,将模型响应给中心控制器
- 前端控制器使用模型与视图渲染视图结果,将结果返回给中心控制器,再将结果返回给请求者。
3. 执行原理
- 图为SpringMVC的一个较完整的流程图。实现表示 SpringMVC框架提供的技术,不需要开发者实现,虚线表示需要开发者实现。
- 执行流程的简要分析:
- DispatcherServlet表示前置控制器,是整个SpringMVC的控制中心。用户发出请求,DispatcherServlet接收请求并拦截请求。
- 我们假设请求的url为:http://localhost:8080/SpringMVC/hello
- 如上url可以拆分成三部分:
- http://localhost:8080:服务器域名
- SpringMVC:部署在服务器上的 web站点
- hello:控制器
- 通过分析,以上url表示为:请求位于服务器localhost:8080上的SpringMVC 站点的hello控制器
- HandlerMapping为处理器映射。DispatcherServlet调用HandlerMapping,HandlerMapping根据请求url查找Handler。
- HandlerExecution表示具体的Handler,其主要作用是根据 url查找控制器,如上url被查找的控制器为:hello
- HandlerExecution将解析后的信息传递给DispatcherServlet,如解析控制器映射的等。
- HandlerAdapter表示处理器适配器,其按照特定的规则去执行Handler。
- Handler让具体的Controller执行。
- Controller将具体的执行信息返回给HandlerAdapter,如ModelAndView。
- HandlerAdapter将视图逻辑名或模型传递给DispatcherServlet。
- DispatcherServlet调用视图解析器(ViewResolver)来解析HandlerAdapter传递的逻辑视图名。
- 视图解析器将解析的逻辑视图名传给DispatcherServlet。
- DispatcherServlet根据视图解析器解析的视图结果,调用具体的视图。
- 最终视图呈现给用户。
- DispatcherServlet表示前置控制器,是整个SpringMVC的控制中心。用户发出请求,DispatcherServlet接收请求并拦截请求。
4.第一个MVC程序
4.1 配置版
-
新建一个Moudle,springmvc-02-hello,添加web的支持
-
导入依赖 pom.xml
<dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.1.9.RELEASE</version> </dependency> <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> </dependencies>
-
配置web.xml,注册DispatcherServlet
<?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"> <!--1. 注册DispatcherServlet--> <servlet> <servlet-name>springmvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!--关联一个SpringMVC的配置文件:[servlet-name] -servlet.xml --> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:springmvc-servlet.xml</param-value> </init-param> <!-- 启动级别-1:表示服务器启动时启动 --> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>springmvc</servlet-name> <url-pattern>/</url-pattern> <!-- / :匹配所有请求(不包括 .jsp)--> <!-- /* :匹配所有请求(包括 .jsp)--> </servlet-mapping> </web-app>
-
编写SpringMVC的配置文件。名称:springmvc-servlet.xml([servletname]-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/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> </beans>
-
添加处理映射器
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
-
添加处理适配器
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
-
添加视图解析器: 注意,要写id
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver"> <!--前缀--> <property name="prefix" value="/WEB-INF/jsp/"/> <!--后缀--> <property name="suffix" value=".jsp"/> </bean>
-
编写我们要操作业务的Controller,实现Controller接口 HelloController.java
package com.zc.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 HelloController implements Controller { public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { //模型和视图 ModelAndView mv = new ModelAndView(); //封装对象,放在ModelAndView中 mv.addObject("msg","HelloSpringMVC"); //封装要跳转的视图,放在ModelAndView中 mv.setViewName("hello"); return mv; } }
-
将自己的类交给SpringIOC容器,注册 bean springmvc-servlet.xml
<!--Handler--> <!--将自己写的类交给SpringIOC容器,注册bean--> <bean id="/aaa" class="com.zc.controller.HelloController"/>
-
写要跳转的jsp页面 hello.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>hello</title> </head> <body> ${msg} </body> </html>
4.2 解决出现的404错误
- 在代码正确的情况下,IDEA 打包时,没有将jar包一起打包
- 解决方案:在 以上界面中,在WEB-INF目录下,创建lib文件夹,添加jar包
4.3 注解版
-
新建一个Moudle,springmvc-03-annotation,添加web的支持
-
导入依赖 pom.xml
<dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.1.9.RELEASE</version> </dependency> <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> </dependencies>
-
配置web.xml,注册DispatcherServlet
<?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"> <!--1.注册Servlet--> <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> <!--所有请求都会被SpringMVC拦截--> <servlet-mapping> <servlet-name>SpringMVC</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> </web-app>
-
编写SpringMVC的配置文件。名称:springmvc-servlet.xml([servletname]-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" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd"> <!-- 自动扫描包,让指定包下的注解生效,由IOC容器统一管理 --> <context:component-scan base-package="com.zc.controller"/> <!-- 让Spring MVC不处理静态资源 --> <mvc:default-servlet-handler /> <!-- 支持mvc注解驱动 在spring中一般采用@RequestMapping注解来完成映射关系 要想使@RequestMapping注解生效 必须向上下文中注册DefaultAnnotationHandlerMapping 和一个AnnotationMethodHandlerAdapter实例 这两个实例分别在类级别和方法级别处理。 而annotation-driven配置帮助我们自动完成上述两个实例的注入。 --> <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>
- 在视图解析器中,我们把所有视图都存放在/WEB-INF/目录下,这样可以保证视图安全,因为这个目录下的文件,客户端不能直接访问。
- 让IOC注解生效
- 静态资源过滤:HTML、.JS、.CSS、图片、视频
- MVC的注解驱动
- 配置视图解析器
- 在视图解析器中,我们把所有视图都存放在/WEB-INF/目录下,这样可以保证视图安全,因为这个目录下的文件,客户端不能直接访问。
-
编写一个Java控制类:com.zc.controller.HelloController
import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; @Controller public class HelloController { @RequestMapping("hello") public String sayHello(Model model){ //向模型中添加属性msg与值,可以在JSP页面中取出并渲染 model.addAttribute("msg","hello,SpringMVC"); return "hello"; } }
- @Controller是为了让Spring IOC容器初始化时自动扫描到
- @RequestMapping是为了映射请求路径。如果类和方法上都有@RequestMapping注解,则请求 路径为 /类上的路径/方法上的路径
- 方法中声明Model类型的参数是为了把Action中的数据带到视图中
- 方法返回的结果是视图的名称hello,加上配置文件中的前后缀变成WEB-INF/jsp/hello.jsp
-
在WEB-INF/ jsp目录中创建hello.jsp , 视图可以直接取出并展示从Controller带回的信息
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>zzz</title>
</head>
<body>
${msg}
</body>
</html>
5. 控制器 Controller
- 控制器负责提供访问应用程序的行为,通常通过就接口定义或注解定义两种方式实现
- 控制器负责解析用户的请求并将其转换为一个模型
- 在Spring MVC中,一个控制器类可以包含多个方法
- 在Spring MVC中,对于Controller的配置方有很多种
5.1 实现Controller接口
5.1.1 Controller接口介绍
Controller是一个接口,在org.springframework.web.servlet.mvc包下,接口中只有一个方法;
//实现该接口的类获得控制器功能
public interface Controller {
//处理请求且返回一个模型与视图对象
ModelAndView handleRequest(HttpServletRequest var1, HttpServletResponse var2) throws Exception;
}
5.1.2 测试
-
新建一个Moudle,springmvc-04-controller
-
编写 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>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-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" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd"> <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类,ControllerTest1.java
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 ControllerTest1 implements Controller { public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { //返回一个模型视图对象 ModelAndView mv = new ModelAndView(); mv.addObject("msg","Test1Controller"); mv.setViewName("test"); return mv; } }
-
编写完毕后,去Spring配置文件中注册请求的bean;name对应请求路径,class对应处理请求的类
<bean name="/t1" class="com.zc.controller.ControllerTest1"/>
-
编写前端test.jsp,注意在WEB-INF/jsp目录下编写,对应我们的视图解析器
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>test1</title> </head> <body> ${msg} </body> </html>
-
说明
- 实现接口Controller定义控制器是较老的办法
- 缺点是:一个控制器中只有一个方法,如果要多个方法则需要定义多个Controller;定义的方式比较麻烦
5.2 使用注解@Controller
-
@Controller注解类型用于声明Spring类的实例是一个控制器
-
Spring可以使用扫描机制来找到应用程序中所有基于注解的控制器类,为了保证Spring能找到你的控制器,需要在配置文件中声明组件扫描。
<!-- 自动扫描指定的包,下面所有注解类交给IOC容器管理 --> <context:component-scan base-package="com.zc.controller"/>
-
增加一个ControllerTest2类,使用注解实现
import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; //@Controller注解的类会自动添加到Spring上下文中 @Controller public class ControllerTest2 { //映射访问路径 @RequestMapping("t2") public String index(Model model){ //Spring MVC会自动实例化一个Model对象用于向视图中传值 model.addAttribute("msg","ControllerTest2"); return "test"; } }
5.3 总结
可以发现,我们的两个请求都可以指向一个视图,但是页面的结果是不一样的,从这里可以看出,视图是复用的,而控制器与视图之间是弱耦合关系。
6. RequestMapping
-
@RequestMapping注解用于映射url到控制器类或一个特定的处理程序方法。可用于类和方法上。用于类上,表示类中所有响应请求的方法都是以该地址作为父路径。
-
只注解在方法上
@Controller public class TestController { @RequestMapping("/h1") public String test(){ return "test"; } }
- 访问路径:http://localhost:8080/h1
-
同时注解类和方法
@Controller @RequestMapping("/admin") public class TestController { @RequestMapping("/h1") public String test(){ return "test"; } }
- 访问路径:http://localhost:8080/admin/h1
7. RestFul风格
7.1 概念
Restful就是一个资源定位及资源操作的风格。不是标准也不是协议,只是一种风格。基于这种风格设计的软件可以更简洁,更有层次 ,更易于实现缓存等机制。
7.2 功能
- 资源定位:互联网所有的事物都可以被抽象为资源
- 资源操作:使用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
- 传统方式操作资源:通过不同的参数来实现不同的效果。方法单一,只有post和get
7.3 测试
-
新建一个类 RestFulController
@Controller public class RestFulController { }
-
在Spring MVC中可以使用 @PathVariable 注解,让方法参数的值对应绑定到一个URI模板变量上
import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; @Controller public class RestFulController { //映射访问路径 @RequestMapping("/add/{a}/{b}") public String index(@PathVariable int a ,@PathVariable int b,Model model){ int res = a+b; ///Spring MVC会自动实例化一个Model对象用于向视图中从传值 model.addAttribute("msg","结果为:"+res); //返回视图位置 return "test"; } }
-
使用路径变量好处:
-
使路径变得更加简介
-
获得参数更加方便,框架会自动进行类型转换
-
通过路径变量的类型可以约束访问参数,如果类型不一样,则访问不到对应的请求方法,例如,如果这里访问的是 /add/1/a,则路径与方法不匹配,而不会是参数转换失败
-
7.4 使用method属性指定请求类型
用于约束请求的类型,可以缩小请求的范围。指定请求谓词的类型为GET、POST、HEAD、OPTIONS、PUT、PATCH、DELETE、TRACE等。
7.5 测试
-
增加一个方法
//映射访问路径,必须是POST请求 @RequestMapping(value = "/hello",method = {RequestMethod.POST}) public String index2(Model model){ model.addAttribute("msg","hello!"); return "test"; }
-
使用浏览器地址栏进行访问默认是GET请求,会报 405 错误
-
如果将POST修改为GET即可正常访问
-
小结:
- Spring MVC 的@RequestMapping 注解能够处理 HTTP 请求的方法,比如 GET,PUT,POST,DELETE 以及 PATCH。
- 所有地址栏请求默认都会是 HTTP GET类型的。
- 方法级别的注解变体有以下几个:组合注解
- @GetMapping
- @PostMapping
- @PutMapping
- @DeleteMapping
- @PatchMapping
- 例如:@GetMapping是一个组合注解,平时会使用的会比较多。它所扮演的是 @RequestMapping(method =RequestMethod.GET) 的一个快捷方式
8. 结果跳转方式
8.1 ModelAndView
-
设置ModelAndView对象,根据View的名称和视图解析器跳转到指定的页面。
-
页面:{视图解析器前缀} + viewName + {视图解析器后缀}
-
视图解析器
<!-- 视图解析器 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver"> <!-- 前缀 --> <property name="prefix" value="/WEB-INF/jsp/" /> <!-- 后缀 --> <property name="suffix" value=".jsp" /> </bean>
-
对应的Controller类
public class ControllerTest1 implements Controller { public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception { //返回一个模型视图对象 ModelAndView mv = new ModelAndView(); mv.addObject("msg","ControllerTest1"); mv.setViewName("test"); return mv; } }
8.2 ServletAPI
-
通过设置ServletAPI,不需要视图解析器
@Controller public class ServletAPITest { //1、通过HttpServletResponse进行输出 @RequestMapping("/result/t1") public void test1(HttpServletRequest req, HttpServletResponse rsp) throws IOException { rsp.getWriter().println("Hello,Spring BY servlet API"); } //2、通过HttpServletResponse实现重定向 @RequestMapping("/result/t2") public void test2(HttpServletRequest req, HttpServletResponse rsp) throws IOException { rsp.sendRedirect("/index.jsp"); } //3、通过HttpServletResponse实现转发 @RequestMapping("/result/t3") public void test3(HttpServletRequest req, HttpServletResponse rsp) throws Exception { //转发 req.setAttribute("msg","/result/t3"); req.getRequestDispatcher("/WEB-INF/jsp/test.jsp").forward(req,rsp); } }
8.3 SpringMVC
8.3.1 通过SpringMVC来实现转发和重定向 - 无需视图解析器
@Controller
public class SpringMVCTest {
@RequestMapping("/sm/t1")
public String test1(){
//转发
return "/index.jsp";
}
@RequestMapping("/sm/t2")
public String test2(){
//转发二
return "forward:/index.jsp";
}
@RequestMapping("/sm/t3")
public String test3(){
//重定向
return "redirect:/index.jsp";
}
}
- 注意:重定向与转发,可以有视图解析器也可以没有
8.3.1 通过SpringMVC来实现转发和重定向 - 有视图解析器
@Controller
public class SpringMVCTest2 {
@RequestMapping("/sm2/t1")
public String test1(){
//转发
return "test";
}
@RequestMapping("/sm2/t2")
public String test2(){
//重定向
return "redirect:/index.jsp";
}
@RequestMapping("/sm2/t3")
public String test3(){
//转发
return "forward:/index.jsp";
}
}
9. 数据处理
9.1 处理提交数据
9.1.1 提交的域名称和处理方法的参数名一致
-
提交数据:http://localhost:8080/user/t1?name=zhangsan
-
处理方法:
@RequestMapping("/user") @Controller public class UserController { @RequestMapping("/t1") public String test1(String name){ System.out.println("t1++++++++"+name); return "test"; } }
-
后台输出:zhangsan
9.1.2 提交的域名称和处理方法的参数名不一致
-
提交数据:http://localhost:8080/user/t1?username=zhangsan
-
处理方法:
@RequestMapping("/user") @Controller public class UserController { @RequestMapping("/t2") public String test2(@RequestParam("username") String name) { System.out.println("t2++++++++"+name); return "test"; } }
-
后台输出:zhangsan
9.1.3 提交的是一个对象
-
提交数据:http://localhost:8080/user/t1?name=zhangsan&age=10&weight=100
-
实体类:
@Data @AllArgsConstructor @NoArgsConstructor public class User { private String name; private int age; private int weight; }
-
处理方法:
@RequestMapping("/user") @Controller public class UserController { @RequestMapping("/t2") public String test2(@RequestParam("username") String name) { System.out.println("t2++++++++"+name); return "test"; } }
-
后台输出:User(name=zhangsan, age=10, weight=100)
-
注意:如果使用对象的话,前端传递的参数名和对象属性名必须一致,否则就是null。
9.2 数据显示到前端
9.2.1 通过ModelAndView
public class ControllerTest1 implements Controller {
public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
//返回一个模型视图对象
ModelAndView mv = new ModelAndView();
mv.addObject("msg","ControllerTest1");
mv.setViewName("test");
return mv;
}
}
9.2.2 通过ModelMap
public class ControllerTest1 implements Controller {
public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
//返回一个模型视图对象
ModelAndView mv = new ModelAndView();
mv.addObject("msg","ControllerTest1");
mv.setViewName("test");
return mv;
}
}
9.2.3 通过Model
@RequestMapping("/hello")
public String hello(@RequestParam("username") String name, Model model){
//封装要显示到视图中的数据
//相当于req.setAttribute("name",name);
model.addAttribute("msg",name);
System.out.println(name);
return "test";
}
9.2.4 三种方式对比
- Model方法较少,简化了新手对于Model对象的操作和理解,适合新手
- ModelMap继承了LinkedMap,除了实现了自身的一些方法,同样的继承了LinkedMap的方法和特性;
- ModelAndView在存储数据的同时,可以进行设置返回的逻辑视图,进行控制展示层的跳转。
9.3 乱码问题
-
编写一个提交的表单 login.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>登录</title> </head> <body> <form action="/login/t1" method="post"> <input type="text" name="name"> <input type="submit"> </form> </body> </html>
-
在后台编写对应的处理类 EncodingController.java
@Controller public class EncodingController { @RequestMapping("/login/t1") public String login(Model model,String name){ model.addAttribute("msg",name); return "test"; } }
-
输入中文测试,发现乱码
-
以前,遇到乱码问题通过过滤器来解决,而SpringMVC给我们提供了一个过滤器,可以在web.xml中配置
-
在web.xml中配置过滤器
<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>
-
可以发现,乱码问题已经被解决
-
如果在某些极端情况下,使用以上方法不能解决乱码问题,处理方法如下:
-
修改tomcat配置文件,设置编码 server.xml
<Connector URIEncoding="utf-8" port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" />
-
自定义过滤器
package com.zc.filter; import javax.servlet.*; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.util.Map; /** * 解决get和post请求 全部乱码的过滤器 */ public class GenericEncodingFilter implements Filter { @Override public void destroy() { } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { //处理response的字符编码 HttpServletResponse myResponse=(HttpServletResponse) response; myResponse.setContentType("text/html;charset=UTF-8"); // 转型为与协议相关对象 HttpServletRequest httpServletRequest = (HttpServletRequest) request; // 对request包装增强 HttpServletRequest myrequest = new MyRequest(httpServletRequest); chain.doFilter(myrequest, response); } @Override public void init(FilterConfig filterConfig) throws ServletException { } } //自定义request对象,HttpServletRequest的包装类 class MyRequest extends HttpServletRequestWrapper { private HttpServletRequest request; //是否编码的标记 private boolean hasEncode; //定义一个可以传入HttpServletRequest对象的构造函数,以便对其进行装饰 public MyRequest(HttpServletRequest request) { super(request);// super必须写 this.request = request; } // 对需要增强方法 进行覆盖 @Override public Map getParameterMap() { // 先获得请求方式 String method = request.getMethod(); if (method.equalsIgnoreCase("post")) { // post请求 try { // 处理post乱码 request.setCharacterEncoding("utf-8"); return request.getParameterMap(); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } } else if (method.equalsIgnoreCase("get")) { // get请求 Map<String, String[]> parameterMap = request.getParameterMap(); if (!hasEncode) { // 确保get手动编码逻辑只运行一次 for (String parameterName : parameterMap.keySet()) { String[] values = parameterMap.get(parameterName); if (values != null) { for (int i = 0; i < values.length; i++) { try { // 处理get乱码 values[i] = new String(values[i] .getBytes("ISO-8859-1"), "utf-8"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } } } } hasEncode = true; } return parameterMap; } return super.getParameterMap(); } //取一个值 @Override public String getParameter(String name) { Map<String, String[]> parameterMap = getParameterMap(); String[] values = parameterMap.get(name); if (values == null) { return null; } return values[0]; // 取回参数的第一个值 } //取所有值 @Override public String[] getParameterValues(String name) { Map<String, String[]> parameterMap = getParameterMap(); String[] values = parameterMap.get(name); return values; } }
-
然后在web.xml中配置这个过滤器即可。
10. JSON
10.1 什么是JSON
10.1.1 简介
- JSON(JavaScript Object Notation,JS对象标记)是一种轻量级的数据交换格式,目前使用特别广泛。
- 采用完全独立于编程语言的文本格式来存储和表示数据。
- 简洁和清晰的层次结构使得JSON成为理想的数据交换语言。
- 易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率。
10.1.2 与JavaScript对象对比
//JavaScript对象
var obj = {name:"zhangsan",age:18,hobby:"java"}
//json字符串
var json = '{"name":"lisi","age":18,"hobby":"game"}'
- JSON是JavaScript对象的字符串表示法,它使用文本表示一个JS对象的信息,本质是一个字符串
- 注意:json字符串中,键 和 值 都需要引号
10.1.3 与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"}'
10.2 测试
-
新建一个module ,springmvc-05-json , 添加web的支持
-
在web目录下新建一个 json01.html , 编写测试内容
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>json</title> <script type="text/javascript"> //编写一个JS对象 var user = { name:"zhangsan", age:18, hobby:"java" }; //将JS对象转换为JSON var json = JSON.stringify(user); //在控制台输出 console.log(json); //编写一个JSON对象 var json2 = '{"name":"lisi","age":18,"hobby":"game"}'; //将JSON对象转换为JS对象 var p = JSON.parse(json2); //在控制台输出 console.log(p); </script> </head> <body> </body> </html>
-
输出
11. Jackson
11.1 什么是Jackson
一种JSON的解析工具
11.2 Jackson的使用
11.2.1 普通对象
-
导入jar包
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.12.5</version> </dependency>
-
编写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>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-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" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd"> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver"> <property name="prefix" value="/WEB-INF/jsp/"/> <property name="suffix" value=".jsp"/> </bean> <context:component-scan base-package="com.zc.controller"/> </beans>
-
编写实体类 User,便于测试
package com.zc.pojo; public class User { private String name; private int age; private int weight; }
-
编写controller,用于测试
package com.zc.controller; @Controller public class JsonController { @RequestMapping("/j1") @ResponseBody public String test1() throws JsonProcessingException { //创建一个jackson的对象映射器用来解析数据 ObjectMapper mapper = new ObjectMapper(); //创建一个对象 User user = new User("张三",18,100); //将对象解析为json格式 String str = mapper.writeValueAsString(user); //由于使用了@ResponseBody注解,这里不会跳转视图 return user.toString()+"++++++"+str; } }
-
测试结果
-
以上Controller进阶写法
@RestController public class JsonController { @RequestMapping("/j1") public String test1() throws JsonProcessingException { //创建一个jackson的对象映射器用来解析数据 ObjectMapper mapper = new ObjectMapper(); //创建一个对象 User user = new User("张三",18,100); //将对象解析为json格式 String str = mapper.writeValueAsString(user); //由于使用了@RestController注解,这里不会跳转视图 return user.toString()+"++++++"+str; } }
- 类上的@RestController注解 等价于 类上的@Controller + @ResponseBody
11.2.2 解决乱码
-
方式一:通过设置@RequestMaping的produces属性来实现
@RequestMapping(value = "/j1",produces = "application/json;charset=utf-8")
-
方式二:通过修改配置文件实现。在springmvc-servlet.xml中加入以下代码:
<mvc:annotation-driven> <mvc:message-converters register-defaults="true"> <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>
11.2.3 集合
-
编写controller,用于测试
package com.zc.controller; @RestController public class JsonController { @RequestMapping("/j2") public String test2() throws JsonProcessingException { ObjectMapper mapper = new ObjectMapper(); List<User> list = new ArrayList<User>(); User user1 = new User("张三1",18,100); User user2 = new User("张三2",18,100); User user3 = new User("张三3",18,100); User user4 = new User("张三4",18,100); User user5 = new User("张三5",18,100); list.add(user1); list.add(user2); list.add(user3); list.add(user4); list.add(user5); String str = mapper.writeValueAsString(list); return str; } }
-
测试结果
11.2.4 时间对象
-
编写controller,用于测试
package com.zc.controller; @RestController public class JsonController { @RequestMapping("j3") public String test3() throws JsonProcessingException { ObjectMapper mapper = new ObjectMapper(); //创建时间对象 Date date = new Date(); return mapper.writeValueAsString(date); } }
-
测试结果
- 默认日期格式会变成一个数字,是1970年1月1日到当前日期的毫秒数!
- Jackson 默认是会把时间转成timestamps形式
-
解决方案:取消默认转换,自定义时间格式
@RequestMapping("j3") public String test3() throws JsonProcessingException { ObjectMapper mapper = new ObjectMapper(); //关闭默认转换 mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS,false); //创建时间对象 Date date = new Date(); //自定义日期格式对象 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); ///指定日期格式 mapper.setDateFormat(sdf); System.out.println(date); return mapper.writeValueAsString(date); }
-
运行结果
12. Fastjson
12.1 什么是Fastjson
12.1.1 概念
fastjson.jar是阿里开发的一款专门用于Java开发的包,可以方便的实现json对象与JavaBean对象的转换,实现Javabean对象与json字符串的转换,实现json对象与json字符串的转换。实现json的转发的方法有很多,但最后的实现结果都是一样的。
12.1.2 三个主要的类
- JSONObject:代表json对象
- JSONObject实现了Map接口, 猜想 JSONObject底层操作是由Map实现的。
- JSONObject对应json对象,通过各种形式的get()方法可以获取json对象中的数据,也可利用诸如size(),isEmpty()等方法获取"键:值"对的个数和判断是否为空。其本质是通过实现Map接口并调用接口中的方法完成的。
- JSONArray:代表json对象数组
- 内部是有List接口中的方法来完成操作的。
- JOSN:代表JSONObject和JSONArray的转化
- JSON类源码分析与使用
- 仔细观察这些方法,主要是实现json对象,json对象数组,javabean对象,json字符串之间的相互转化。
12.2 Fastjson的使用
-
导入依赖
<dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.60</version> </dependency>
-
创建Controller ,测试
package com.zc.controller; @RestController public class JsonController { @RequestMapping("/j4") public String test4(){ ObjectMapper mapper = new ObjectMapper(); List<User> list = new ArrayList<User>(); User user1 = new User("张三1",18,100); User user2 = new User("张三2",18,100); User user3 = new User("张三3",18,100); User user4 = new User("张三4",18,100); User user5 = new User("张三5",18,100); list.add(user1); list.add(user2); list.add(user3); list.add(user4); list.add(user5); System.out.println("*******Java对象 转 JSON字符串*******"); String str1 = JSON.toJSONString(list); System.out.println("JSON.toJSONString(list)==>"+str1); String str2 = JSON.toJSONString(user1); System.out.println("JSON.toJSONString(user1)==>"+str2); System.out.println("\n****** JSON字符串 转 Java对象*******"); User jp_user1=JSON.parseObject(str2,User.class); System.out.println("JSON.parseObject(str2,User.class)==>"+jp_user1); System.out.println("\n****** Java对象 转 JSON对象 ******"); JSONObject jsonObject1 = (JSONObject) JSON.toJSON(user2); System.out.println("(JSONObject) JSON.toJSON(user2)==>"+jsonObject1.getString("name")); System.out.println("\n****** JSON对象 转 Java对象 ******"); User to_java_user = JSON.toJavaObject(jsonObject1, User.class); System.out.println("JSON.toJavaObject(jsonObject1, User.class)==>"+to_java_user); return "hello"; } }
-
运行结果
13. 整合SSM
13.1 基本环境搭建
-
创建数据库、数据表
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=utf8; INSERT INTO `books`(`bookID`,`bookName`,`bookCounts`,`detail`)VALUES (1,'Java',1,'从入门到放弃'), (2,'MySQL',10,'从删库到跑路'), (3,'Linux',5,'从进门到进牢');
-
新建一个maven项目,ssmbuild,添加web支持
-
导入相关依赖
<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> <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.20</version> <scope>provided</scope> </dependency> </dependencies>
-
Maven资源过滤设置
<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>
-
建立基本结构和配置框架
-
com.zc.controller
-
com.zc.dao
-
com.zc.pojo
-
com.zc.service
-
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" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> </beans>
-
mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> </configuration>
-
13.2 Mybatis层编写
-
数据库配置文件 database.properties
jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/ssmbuild jdbc.username=root jdbc.password=ZC520
-
IDEA关联数据库
-
编写Mybatis的核心配置文件
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <typeAliases> <package name="com.zc.pojo"/> </typeAliases> </configuration>
-
编写数据库对应的实体类 Books
package com.zc.pojo; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @Data @AllArgsConstructor @NoArgsConstructor public class Books { private int bookID; private String bookName; private int bookCounts; private String detail; }
-
编写Dao层的Mapper接口
package com.zc.dao; import com.zc.pojo.Books; import org.apache.ibatis.annotations.Param; import java.util.List; public interface BooksMapper { //增加一个Book int addBook(Books books); //根据id删除一个Book int deleteBookById(@Param("bookID") int id); //根据id更新一个Book int updateBook(Books books); //根据id查询Book Books queryBookById(@Param("bookID") int id); //查询所有Book List<Books> queryAllBook(); }
-
编写接口对应的Mapper.xml文件 BooksMapper.xml
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.zc.dao.BooksMapper"> <!--增加一个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> <!--根据id更新一个Book--> <update id="updateBook" parameterType="Books"> UPDATE ssmbuild.books SET bookName=#{bookName},bookCounts=#{bookCounts},detail=#{detail} WHERE bookID = #{bookID} </update> <!--根据id查询Book--> <select id="queryBookById" resultType="Books"> SELECT * FROM ssmbuild.books WHERE bookID=#{bookID} </select> <!--查询所有Book--> <select id="queryAllBook" resultType="Books"> SELECT * FROM ssmbuild.books </select> </mapper>
-
在mybatis的核心配置文件中,配置UserMapper.xml的路径
<mappers> <mapper resource="com/zc/dao/BooksMapper.xml"></mapper> </mappers>
-
编写Service层的接口
package com.zc.service; import com.zc.pojo.Books; import org.apache.ibatis.annotations.Param; import java.util.List; public interface BooksService { //增加一个Book int addBook(Books books); //根据id删除一个Book int deleteBookById(int id); //根据id更新一个Book int updateBook(Books books); //根据id查询Book Books queryBookById(int id); //查询所有Book List<Books> queryAllBook(); }
-
编写Service层的实现类
package com.zc.service; import com.zc.dao.BooksMapper; import com.zc.pojo.Books; import java.util.List; public class BooksServiceImpl implements BooksService { //调用dao层的操作,设置一个set接口,方便Spring管理 private BooksMapper booksMapper; public void setBooksMapper(BooksMapper booksMapper) { this.booksMapper = booksMapper; } public int addBook(Books books) { return booksMapper.addBook(books); } public int deleteBookById(int id) { return booksMapper.deleteBookById(id); } public int updateBook(Books books) { return booksMapper.updateBook(books); } public Books queryBookById(int id) { return booksMapper.queryBookById(id); } public List<Books> queryAllBook() { return booksMapper.queryAllBook(); } }
13.3 Spring层编写
-
配置Spring整合MyBatis,数据源使用c3p0
-
编写Spring整合Mybatis的相关配置文件 spring-dao.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/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://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"/> <!--配置MyBatis全局配置文件: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--> <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/> <!--给出需要扫描Dao接口包--> <property name="basePackage" value="com.zc.dao"/> </bean> </beans>
-
Spring整合service层
-
编写Spring整合service层的相关配置文件 spring-service.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/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!--扫描service相关的bean--> <context:component-scan base-package="com.zc.service"/> <!--BookServiceImpl注入到IOC容器中--> <bean id="booksServiceImpl" class="com.zc.service.BooksServiceImpl"> <property name="booksMapper" ref="booksMapper"/> </bean> <!--配置事务管理器--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <!--注入数据库连接池--> <property name="dataSource" ref="datasource"/> </bean> </beans>
13.4 SpringMVC层编写
-
编写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>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> <!--过滤器--> <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-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/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd"> <!--配置SpringMVC--> <!--1.开启SpringMVC注解驱动--> <mvc:annotation-driven/> <!--2.静态资源默认Servlet配置--> <mvc:default-servlet-handler/> <!--3.配置jsp 视图解析器--> <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.zc.controller"/> </beans>
-
Spring配置整合文件,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" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <import resource="spring-dao.xml"/> <import resource="spring-service.xml"/> <import resource="spring-mvc.xml"/> </beans>
13.5 查询所有书籍功能实现
-
编写Controller,处理请求,BooksController
package com.zc.controller; @RequestMapping("/book") @Controller public class BooksController { @Autowired private BooksService booksService; @RequestMapping("/list") public String list(Model model){ List<Books> list = booksService.queryAllBook(); model.addAttribute("list",list); return "list"; } }
-
编写jsp,展示书籍信息,list.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> <!-- 引入 Bootstrap --> <link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"> </head> <body> <div class="row clear"> <div class="col-md-12 column"> <table class="table table-hover table-striped"> <thead> <tr> <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> </tr> </c:forEach> </tbody> </table> </div> </div> </body> </html>
-
效果截图
14. Ajax
14.1 简介
-
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用户界面。
14.2 作用
- 注册时,输入用户名自动检测用户是否以及存在。
- 登录时,提示用户名、密码错误
- 删除数据行时,将行ID发送到后台,后台在数据库中删除,数据库删除成功后,在页面DOM中将数据行也删除。
- …
14.3 jQuery.ajax
14.3.1 简介
-
为了方便学习和使用,我们使用jquery提供的Ajax,而不去追究纯JS原生实现Ajax的原理
-
Ajax的核心是XMLHttpRequest对象(XHR)。XHR为向服务器发送请求和解析服务器响应提供了接口。能够以异步方式从服务器获取新数据。
-
jQuery提供多个与AJAX有关的方法。
-
通过jQuery AJAX方法,能够使用 HTTP Get 和 HTTP Post 从远程服务器上请求文本、HTML、XML或JSON,同时,能够把这些外部数据直接载入网页的被选元素中。
-
jQuery不是生产者,而是大自然的搬运工。
-
jQuery Ajax的本质就是 XMLHttpRequest,对XMLHttpRequest进行封装,方便调用。
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 将自动替换 ? 为正确的函数名,以执行回调函数
14.3.2 测试1 - 输入框失去鼠标焦点后,在控制台输出
-
新建springmvc-06-ajax模块,添加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" xmlns:context="http://www.springframework.org/schema/context" 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-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" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd"> <!--自动扫描指定的包,下面所有注解类交给IOC容器管理--> <context:component-scan base-package="com.zc.controller"/> <mvc:default-servlet-handler/> <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>
-
编写一个controller,便于测试。AjaxController.java
package com.zc.controller; @Controller public class AjaxController { @RequestMapping("/ajax1") public void ajax1(String name, HttpServletResponse response) throws IOException { if("zhangsan".equals(name)){ response.getWriter().print("true"); }else { response.getWriter().print("false"); } } //访问ajax.jsp @RequestMapping("ajax2") public String ajax2(){ return "ajax"; } }
-
导入jQuery,可以使用在线CDN或者下载到本地之后导入
<%--使用在线的CDN--%> <%--<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>--%> <%--使用本地--%> <script src="${pageContext.request.contextPath}/js/jquery-3.6.0.js"></script>
-
编写ajax.jsp进行测试
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>ajax测试</title> <%--使用在线的CDN--%> <%--<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>--%> <%--使用本地--%> <script src="${pageContext.request.contextPath}/js/jquery-3.6.0.js"></script> <script> function a1() { $.post({ url:"${pageContext.request.contextPath}/ajax1", data:{'name':$("#txtName").val()}, success:function (data,status) { console.log("data==="+data); console.log("status=="+status) } }); } </script> </head> <body> <%--onblur:失去焦点触发事件--%> 用户名:<input type="text" name="" id="txtName" οnblur="a1()"/> </body> </html>
-
测试结果
14.3.3 测试2 - 点击按钮后,加载后台数据
-
新建实体类 user
package com.zc.pojo; @Data @AllArgsConstructor @NoArgsConstructor public class User { private int uid; private String name; private int age; }
-
新建controller,向前端传数据
package com.zc.controller; @Controller public class AjaxController { @RequestMapping("ajax2") @ResponseBody public List<User> ajax2(){ List<User> list = new ArrayList<User>(); list.add(new User(1,"张三",18)); list.add(new User(2,"张三三",18)); list.add(new User(3,"张三三三三",18)); return list; } }
-
新建ajax2.jsp,用于测试
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>ajax2测试</title> <script src="${pageContext.request.contextPath}/js/jquery-3.6.0.js"></script> <script> $(function () { $("#btn").click(function () { $.post("${pageContext.request.contextPath}/ajax2",function (data) { var html=""; for(var i = 0;i<data.length;i++){ html +="<tr>"+ "<td>"+data[i].uid+"</td>"+ "<td>"+data[i].name+"</td>"+ "<td>"+data[i].age+"</td>"+ "</tr>" } $("#content").html(html); }); }); }); </script> </head> <body> <input type="button" value="加载数据" id="btn"> <table> <tr> <td>uid</td> <td>name</td> <td>age</td> </tr> <tbody id="content"> </tbody> </table> </body> </html>
-
测试结果
14.3.4 测试3 - 登录验证
-
修改springmvc-servlet.xml,向其中添加 解决json乱码问题的代码
<mvc:annotation-driven> <mvc:message-converters register-defaults="true"> <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>
-
新建controller,向前端传数据
package com.zc.controller; @Controller public class AjaxController { @ResponseBody @RequestMapping("ajax3") public String ajax3(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; } }
-
新建login.jsp,测试ajax
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>登录页面</title> <script src="${pageContext.request.contextPath}/js/jquery-3.6.0.js"></script> <script> function a1() { $.post({ url: "${pageContext.request.contextPath}/ajax3", data: {'name': $("#loginName").val()}, success: function (data) { if (data.toString() == 'OK') { $("#userInfo").css("color", "green"); } else { $("#userInfo").css("color", "red"); } $("#userInfo").html(data); } }); } function a2() { $.post({ url:"${pageContext.request.contextPath}/ajax3", data:{'pwd':$("#password").val()}, success:function (data) { if(data.toString()=='OK'){ $("#pwdInfo").css("color","green"); }else { $("#pwdInfo").css("color","red"); } $("#pwdInfo").html(data); } }) } </script> </head> <body> 用户名:<input type="text" id="loginName" οnblur="a1()"> <span id="userInfo"></span> <br> 密 码:<input type="password" id="password" οnblur="a2()"> <span id="pwdInfo"></span> </body> </html>
-
测试结果
15. 拦截器
15.1 概述
15.1.1 介绍
SpringMVC的处理器拦截器类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理。开发者可以自己定义一些拦截器来实现特点的功能。
15.1.2 过滤器与拦截器区别
- 过滤器
- Servlet规范中的一部分,任何javaweb工程都可以使用
- 在url-pattern中配置了/*之后,可以对所有要访问的资源进行拦截
- 拦截器
- 拦截器是SpringMVC框架自己的,只有使用了SpringMVC框架的工程才能使用
- 拦截器只会拦截访问的控制器方法,如果访问的是jsp/html/css/image/js是不会进行拦截的
- 拦截器是AOP思想的具体应用
15.2 自定义拦截器
-
新建Moudle,springmvc-07-Interceptor,添加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"> <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-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" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd"> <!--自动扫描指定的包,下面所有注解类交给IOC容器管理--> <context:component-scan base-package="com.zc.controller"/> <mvc:default-servlet-handler/> <mvc:annotation-driven> <mvc:message-converters register-defaults="true"> <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> <!--视图解析器--> <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,用于测试
package com.zc.controller; @Controller public class TestController { @RequestMapping("t1") @ResponseBody public String test1(){ System.out.println("TestController -> test1() 执行了"); return "OK"; } }
-
编写一个拦截器
package com.zc.interceptor; public class Interceptor implements HandlerInterceptor { //在请求处理的方法之前执行 //如果返回true,则执行下一个拦截器 //如果返回false,就不执行下一个拦截器 public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("=================处理前============="); return true; } //在请求处理方法执行之后执行 public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("============处理后================"); } //在dispatcherServlet处理后执行,做清理工作 public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("============清理===================="); } }
-
在springmvc的配置文件中配置拦截器
<!--关于拦截器的配置--> <mvc:interceptors> <mvc:interceptor> <!--/**:包括路径及其子路径--> <!--例如:/admin/**:拦截的是/admin/add等等,而/admin/add/user不会被拦截--> <!--/admin/**:拦截的是/admin/下的所有--> <mvc:mapping path="/**"/> <!--bean配置的就是拦截器--> <bean class="com.zc.interceptor.Interceptor"/> </mvc:interceptor> </mvc:interceptors>
-
测试结果
16. 文件上传/下载
16.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:除了把空格转换为 “+” 号外,其他字符都不做编码处理,这种方式适用直接通过表单发送邮件。
- 一旦设置了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的组件。
16.2 准备工作
-
新建Module,springmvc-08-file,添加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"> <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-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" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd"> <!--自动扫描指定的包,下面所有注解类交给IOC容器管理--> <context:component-scan base-package="com.zc.controller"/> <mvc:default-servlet-handler/> <mvc:annotation-driven> <mvc:message-converters register-defaults="true"> <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> <!--视图解析器--> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver"> <!--前缀--> <property name="prefix" value="/WEB-INF/jsp/"/> <!--后缀--> <property name="suffix" value=".jsp"/> </bean> </beans>
-
导入文件上传的jar包,commons-fileupload,Maven会自动帮我们导入他的依赖包,commons-io包
<!--文件上传--> <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>
-
在springmvc-servlet.xml文件中配置bean multipartResolver
<!--文件上传配置--> <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>
- 注意:这个bena的id必须为:multipartResolver , 否则上传文件会报400的错误
- CommonsMultipartFile 的 常用方法:
- String getOriginalFilename():获取上传文件的原名
- InputStream getInputStream():获取文件流
- void transferTo(File dest):将上传文件保存到一个目录文件中
16.3 上传文件实例
-
前端页面
<h1>方式一:</h1> <form action="/upload1" enctype="multipart/form-data" method="post"> <input type="file" name="file"/> <input type="submit" value="upload"> </form> <h1>方式二:</h1> <form action="/upload2" enctype="multipart/form-data" method="post"> <input type="file" name="file"/> <input type="submit" value="upload"> </form>
-
Controller
package com.zc.controller; @RestController public class FileController { //方式一: //@RequestParam("file") 将name=file控件得到的文件封装成CommonsMultipartFile 对象 //批量上传CommonsMultipartFile则为数组即可 @RequestMapping("/upload1") 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"; } //方式二: /* * 采用file.Transto 来保存上传的文件 */ @RequestMapping("/upload2") public String fileUpload2(@RequestParam("file") CommonsMultipartFile file, HttpServletRequest request) throws IOException { //上传路径保存设置 String path = request.getServletContext().getRealPath("/upload"); File realPath = new File(path); if (!realPath.exists()){ realPath.mkdir(); } //上传文件地址 System.out.println("上传文件保存地址:"+realPath); //通过CommonsMultipartFile的方法直接写文件(注意这个时候) file.transferTo(new File(realPath +"/"+ file.getOriginalFilename())); return "redirect:/index.jsp"; } }
16.4 下载文件
-
前端页面
<h1>文件下载:</h1> <a href="/download">点击下载</a>
-
Controller
package com.zc.controller; @RestController public class FileController { //文件下载 @RequestMapping(value="/download") public String downloads(HttpServletResponse response , HttpServletRequest request) throws Exception{ //要下载的图片地址 String path = request.getServletContext().getRealPath("/upload"); String fileName = "考研规划.pdf"; //1、设置response 响应头 response.reset(); //设置页面不缓存,清空buffer response.setCharacterEncoding("UTF-8"); //字符编码 response.setContentType("multipart/form-data"); //二进制传输数据 //设置响应头 response.setHeader("Content-Disposition", "attachment;fileName="+ URLEncoder.encode(fileName, "UTF-8")); File file = new File(path,fileName); //2、 读取文件--输入流 InputStream input=new FileInputStream(file); //3、 写出文件--输出流 OutputStream out = response.getOutputStream(); byte[] buff =new byte[1024]; int index=0; //4、执行 写出操作 while((index= input.read(buff))!= -1){ out.write(buff, 0, index); out.flush(); } out.close(); input.close(); return "OK"; } }