SpringMVC
MVC(Model View Controller)
1. MVC 1.1 简介
MVC是一种软件设计规范
Model(模型):数据模型,提供要展示的数据,因此包含数据和行为,可以认为是领域模型或JavaBean组件(包含数据和行为),不过现在一般都分离开来:Value Object(数据Dao) 和 服务层(行为Service)。也就是模型提供了模型数据查询和模型数据的状态更新等功能,包括数据和业务
Controller(控制器):接收用户请求,委托给模型进行处理(状态改变),处理完毕后把返回的模型数据返回给视图,由视图负责展示。也就是说控制器做了个调度员的工作
将业务逻辑 、数据 、显示分离 的方法来组织代码
主要作用:降低视图与业务逻辑间的双向偶合
典型MVC - SMBMS(JSP+servlet+javabean)
:thought_balloon: POJO的划分
:thought_balloon: 各层命名规范
[强制] 类名使用 UpperCamelCase 风格,必须遵从驼峰形式,但以下情形例外:DO / BO /DTO / VO / AO 正例:MarcoPolo / UserDO / XmlService / TcpUdpDeal / TaPromotion
[参考]
Service/DAO层方法命名规约
获取单个对象的方法用get做前缀。
获取多个对象的方法用list做前缀。
获取统计值的方法用count做前缀。
插入的方法用save/insert做前缀。
删除的方法用remove/delete做前缀。
修改的方法用update做前缀。
领域模型命名规约
数据对象:xxxDO,xxx即为数据表名。
数据传输对象:xxxDTO,xxx为业务领域相关的名称。
展示对象:xxxVO,xxx一般为网页名称。
POJO是DO/DTO/BO/VO的统称,禁止命名成xxxPOJO。
:thought_balloon: OOP规约
[强制] 定义 DO/DTO/VO 等 POJO 类时,不要设定任何属性默认值
1.2 Mode1时代
优点:架构简单,比较适合小型项目开发
缺点:JSP职责不单一,职责过重,不便于维护;
1.3 Model2时代
职责划分
Controller
取得表单数据
调用业务逻辑
转向指定的页面
Model
业务逻辑
保存数据的状态
View
显示页面
提高的代码的复用率与项目的扩展性,且大大降低了项目的维护成本
常见的服务器端MVC框架有:Struts、Spring MVC、ASP.NET MVC、Zend Framework、JSF
常见前端MVC框架:vue、angularjs、react、backbone
由MVC演化出了另外一些模式如:MVP、MVVM 等等….
2. SpringMVC 2.1 简介
Spring MVC是Spring Framework的一部分,是基于Java实现MVC的轻量级Web框架
特点 - ==主流,用的人多==
轻量级,简单易学
高效 , 基于请求响应的MVC框架
与Spring兼容性好,无缝结合
约定优于配置
功能强大:RESTful、数据验证、格式化、本地化、主题等
简洁灵活
2.2 中心控制器(DispatcherServlet)
2.3 执行流程
DispatcherServlet
表示前置控制器,是整个SpringMVC的控制中心。用户发出请求,DispatcherServlet接收请求并拦截请求
假设请求url为 http://localhost:8080/SpringMVC/hello
拆分 - 请求位于服务器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
根据视图解析器解析的视图结果,调用具体的视图
最终视图呈现给用户
2.4 使用(配置版) 2.4.1 web.xml 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 <?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" metadata-complete ="true" > <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 >
2.4.2 springmvc-servlet.xml 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 <?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" > <bean class ="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" /> <bean class ="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter" /> <bean class ="org.springframework.web.servlet.view.InternalResourceViewResolver" > <property name ="prefix" value ="/WEB-INF/jsp/" /> <property name ="suffix" value =".jsp" /> </bean > <bean id ="/hello" class ="com.bayyy.controller.HelloController" /> </beans >
2.4.3 Controller 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public class HelloController implements Controller { @Override public ModelAndView handleRequest (HttpServletRequest request, HttpServletResponse response) throws Exception { ModelAndView mv = new ModelAndView (); String result = "HelloSpringMVC" ; mv.addObject("msg" , result); mv.setViewName("test" ); return mv; } }
2.5 使用(注解版) 2.5.1 web.xml
:key: 基本不需要修改
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 <?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 >
2.5.2 springmvc-servlet.xml
为了支持基于注解的IOC,设置了自动扫描包的功能
让IOC的注解生效
静态资源过滤 :HTML . JS . CSS . 图片 , 视频 …..
MVC的注解驱动
配置视图解析器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 <?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 https://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" > <context:component-scan base-package ="com.bayyy.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 >
2.5.3 Controller实现
@Controller是为了让Spring IOC容器初始化时自动扫描到;
@RequestMapping是为了映射请求路径,这里因为类与方法上都有映射所以访问时应该是/hello/h1;
方法中声明Model类型的参数是为了把Action中的数据带到视图中;
方法返回的结果是视图的名称hello,加上配置文件中的前后缀变成WEB-INF/jsp/hello .jsp。
1 2 3 4 5 6 7 8 9 10 11 12 @Controller @RequestMapping("/hello") public class HelloController { @RequestMapping("/h1") public String hello (Model model) { model.addAttribute("msg" , "HelloSpringMVCAnnotation" ); System.out.println("hello" ); return "hello" ; } }
2.5.4 视图层
在WEB-INF/ jsp目录中创建hello.jsp,视图可以直接取出并展示从Controller带回的信息;
可以通过EL表示取出Model中存放的值,或者对象
测试结果:
2.6 步骤总结
处理器映射器、处理器适配器、视图解析器
通常,我们只需要手动配置视图解析器 ,而处理器映射器 和处理器适配器 只需要开启注解驱动 即可,而省去了大段的xml配置
3. RestFul和控制器 3.1 控制器Controller
控制器复杂提供访问应用程序的行为,通常通过接口定义或注解定义两种方法实现。
控制器负责解析用户的请求并将其转换为一个模型。
在Spring MVC中一个控制器类可以包含多个方法
在Spring MVC中,对于Controller的配置方式有很多种
3.2 实现Controller接口
web.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 <?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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 <?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 https://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" > <context:component-scan base-package ="com.bayyy.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 > <bean id ="/test" class ="com.bayyy.controller.ControllerTest1" /> </beans >
Controller
实现 Controller
接口的类获得控制器功能
1 2 3 4 5 6 7 8 9 public class ControllerTest1 implements Controller { @Override public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { ModelAndView mv = new ModelAndView(); mv.addObject("msg","ControllerTest1"); mv.setViewName("test"); return mv; } }
3.3 使用注解 @Controller
web.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 <?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
Spring可以使用扫描机制来找到应用程序中所有基于注解的控制器类,为了保证Spring能找到你的控制器,需要在配置文件中声明组件扫描。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 <?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 https://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" > <context:component-scan base-package ="com.bayyy.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
@Controller注解类型用于声明Spring类的实例是一个控制器
1 2 3 4 5 6 7 8 @Controller public class ControllerTest2 { @RequestMapping("/t2") public String test1 (Model model) { model.addAttribute("msg" ,"ControllerTest2" ); return "test" ; } }
测试结果:
3.4 @RequestMapping
@RequestMapping注解用于映射url到控制器类或一个特定的处理程序方法。可用于类或方法上。用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径
1 2 3 4 5 6 7 8 9 @Controller @RequestMapping("/c3") public class ControllerTest3 { @RequestMapping("/t1") public String test1 () { System.out.println("ControllerTest3" ); return "test" ; } }
3.5 RestFul风格
3.5.1 传统风格 1 2 3 4 5 6 7 8 9 @Controller public class RestFulController { @RequestMapping("/add") public String test1 (int a, int b, Model model) { int res = a + b; model.addAttribute("msg" ,"结果为" + res); return "test" ; } }
测试结果:
3.5.2 RestFul风格 1 2 3 4 5 6 7 8 9 10 11 12 @Controller public class RestFulController { @RequestMapping("/add/{a}/{b}") public String test1 (int a, int b, Model model) { int res = a + b; model.addAttribute("msg" ,"结果为" + res); return "test" ; } }
测试结果:
修改参数类型:
```java @Controller public class RestFulController {// RestFul:http://localhost:8080/add/2/%22bayyy%22
@RequestMapping("/add/{a}/{b}")
public String test1(@PathVariable int a, @PathVariable String b, Model model) {
String res = a + b;
model.addAttribute("msg","a=" + a + " b=" + b +" 结果为" + res);
return "test";
}
}1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 - 测试结果:![image-20230723160057278](https://s2.loli.net/2023/07/23/m893ONtEuBGZAVd.png) ### 3.5.3 使用method属性指定请求类型 > 用于约束请求的类型,可以收窄请求范围。指定请求谓词的类型如GET, POST, HEAD, OPTIONS, PUT, PATCH, DELETE, TRACE等 > > :pushpin: 地址栏输入默认为 ==HTTP GET== 类型 ```java @Controller public class RestFulController { // 原来的:http://localhost:8080/add?a=1&b=2 // RestFul:http://localhost:8080/add/1/2 // @PathVariable 路径变量: 获得路径中的值 @RequestMapping(value = "/add/{a}/{b}", method = RequestMethod.GET) public String test1(@PathVariable int a, @PathVariable String b, Model model) { String res = a + b; model.addAttribute("msg","a=" + a + " b=" + b +" 结果为" + res); return "test"; } }
方法级别的注释变体 - 组合注解
@GetMapping
等效于 @RequestMapping(method =RequestMethod.GET)
@PostMapping
@PutMapping
@DeleteMapping
@PatchMapping
4. 数据处理和跳转 4.1 结果跳转方式
设置ModelAndView对象 , 根据view的名称 , 和视图解析器跳到指定的页面 .
页面 : {视图解析器前缀} + viewName +{视图解析器后缀}
1 2 3 4 5 6 7 8 <bean class ="org.springframework.web.servlet.view.InternalResourceViewResolver" id ="internalResourceViewResolver" > <property name ="prefix" value ="/WEB-INF/jsp/" /> <property name ="suffix" value =".jsp" /> </bean >
1 2 3 4 5 6 7 8 9 10 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; } }
跳转到 /WEB-INF/jsp/test.jsp
4.1.1 ServletAPI
通过HttpServletResponse进行输出
通过HttpServletResponse实现重定向
通过HttpServletResponse实现转发
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 @Controller public class ResultGo { @RequestMapping("/result/t1") public void test1 (HttpServletRequest req, HttpServletResponse rsp) throws IOException { rsp.getWriter().println("Hello,Spring BY servlet API" ); } @RequestMapping("/result/t2") public void test2 (HttpServletRequest req, HttpServletResponse rsp) throws IOException { rsp.sendRedirect("/index.jsp" ); } @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); } }
4.1.2 SpringMVC - 无视图解析器
通过SpringMVC来实现转发和重定向 - 无需视图解析器;
```xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 ```java @Controller public class ResultGoSpringMVC { @RequestMapping("/r2/t1") public String test1(Model model) throws Exception { model.addAttribute("msg", "/WEB-INF/jsp/test.jsp"); // 转发到视图 return "/WEB-INF/jsp/test.jsp"; } @RequestMapping("/r2/t2") public String test3(Model model) throws Exception { model.addAttribute("msg", "forward:/test.jsp"); // 转发到视图 return "forward:/WEB-INF/jsp/test.jsp"; } @RequestMapping("/r2/t3") public String test2(Model model) throws Exception { // model.addAttribute("msg", "redirect:/test.jsp"); // 重定向到视图 return "redirect:/WEB-INF/jsp/test.jsp"; } }
4.1.3 SpringMVC - 有视图解析器
默认为转发,加上 redirect:
为重定向
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 @Controller public class ResultSpringMVC2 { @RequestMapping("/rsm2/t1") public String test1 () { return "test" ; } @RequestMapping("/rsm2/t2") public String test2 () { return "redirect:/index.jsp" ; } }
4.2 数据处理 4.2.1 处理提交数据 1)提交的域名和处理方法的参数一致 提交数据 :localhost:8080/u/t1?name=bayyy
处理方法:
1 2 3 4 5 6 7 8 9 10 @GetMapping("/t1") public String test1 (String name, Model model) { System.out.println("接收到前端的参数为:" + name); model.addAttribute("msg" , name); return "test" ; }
2)提交的域名和处理方法的参数不一致 提交数据 :localhost:8080/u/t2?username=bayyy
处理方法:
1 2 3 4 5 6 7 8 9 10 11 @GetMapping("/t2") public String test2 (@RequestParam("username") String name, Model model) { System.out.println("接收到前端的参数为:" + name); model.addAttribute("msg" , name); return "test" ; }
3)提交一个对象
提交的表单域和对象的属性名一致 , 参数使用对象即可
:warning: 传递参数名和对象名必须一致
提交数据 : localhost:8080/u/t3?id=1&name=bayyy&age=18
处理方法:
1 2 3 4 5 6 7 8 9 10 11 @GetMapping("/t3") public String test3 (User user, Model model) { System.out.println("接收到前端的参数为:" + user); model.addAttribute("msg" , user); return "test" ; }
但是如果属性名不一致:
4.3 数据显示到前端 4.3.1 ModelAndView
实现接口使用
1 2 3 4 5 6 7 8 9 10 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; } }
4.3.2 ModelMap 1 2 3 4 5 6 7 8 @RequestMapping("/hello") public String hello (@RequestParam("username") String name, ModelMap model) { model.addAttribute("name" ,name); System.out.println(name); return "hello" ; }
4.3.3 Model
精简的 ModelMap
1 2 3 4 5 6 7 8 @RequestMapping("/ct2/hello") public String hello (@RequestParam("username") String name, Model model) { model.addAttribute("msg" ,name); System.out.println(name); return "test" ; }
4.4 乱码问题 4.4.1 SpringMVC过滤器 1 2 3 4 5 6 7 8 9 10 11 12 <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 >
个别情况下对get的支持不好
4.4.2 更通用的方法 1)修改Tomcat配置文件:设置编码 1 2 3 4 5 <Connector port ="8080" protocol ="HTTP/1.1" connectionTimeout ="20000" redirectPort ="8443" maxParameterCount ="1000" />
2)自定义过滤器 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 package com.bayyy.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;public class GenericEncodingFilter implements Filter { @Override public void destroy () { } @Override public void doFilter (ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletResponse myResponse=(HttpServletResponse) response; myResponse.setContentType("text/html;charset=UTF-8" ); HttpServletRequest httpServletRequest = (HttpServletRequest) request; HttpServletRequest myrequest = new MyRequest (httpServletRequest); chain.doFilter(myrequest, response); } @Override public void init (FilterConfig filterConfig) throws ServletException { } } class MyRequest extends HttpServletRequestWrapper { private HttpServletRequest request; private boolean hasEncode; public MyRequest (HttpServletRequest request) { super (request); this .request = request; } @Override public Map getParameterMap () { String method = request.getMethod(); if (method.equalsIgnoreCase("post" )) { try { request.setCharacterEncoding("utf-8" ); return request.getParameterMap(); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } } else if (method.equalsIgnoreCase("get" )) { Map<String, String[]> parameterMap = request.getParameterMap(); if (!hasEncode) { for (String parameterName : parameterMap.keySet()) { String[] values = parameterMap.get(parameterName); if (values != null ) { for (int i = 0 ; i < values.length; i++) { try { 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; } }
3)xml注册 1 2 3 4 5 6 7 8 <filter > <filter-name > encoding</filter-name > <filter-class > com.bayyy.filter.GenericEncodingFilter</filter-class > </filter > <filter-mapping > <filter-name > encoding</filter-name > <url-pattern > /*</url-pattern > </filter-mapping >
5. JSON交互处理 5.1 JSON简介
JSON :JavaScript Object Notation, JS 对象标记,是一种轻量级的数据交换格式,采用完全独立于编程语言的文本格式 来存储和表示数据
在 JavaScript 语言中,一切都是对象
因此,任何JavaScript 支持的类型都可以通过 JSON 来表示,例如字符串、数字、对象、数组等。
语法格式:
对象表示为键值对,数据由逗号分隔
花括号保存对象
方括号保存数组
1 2 3 { "name" : "bayyy" } { "age" : "18" } { "sex" : "男" }
优点:易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率
JSON 是 JavaScript 对象的字符串表示法,它使用文本表示一个 JS 对象的信息,本质是一个字符串
5.2 JSON和JS互转 1 2 3 4 5 6 7 8 9 10 11 12 var user = { name : "bayyy" , age : 18 , sex : "男" } var jsonStr = JSON .stringify (user);console .log (jsonStr);var jsonObj = JSON .parse (jsonStr);console .log (jsonObj);
5.3 Controller返回JSON对象 5.3.1 基本使用 ObjectMapper
导包
我们这里使用Jackson,使用它需要导入它的jar包;
当然工具不止这一个,比如还有阿里巴巴的 fastjson 等等
1 2 3 4 5 6 <dependency > <groupId > com.fasterxml.jackson.core</groupId > <artifactId > jackson-databind</artifactId > <version > 2.15.2</version > </dependency >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 <?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 > <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 > </web-app >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 <?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" > <context:component-scan base-package ="com.bayyy.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
produces
解决json乱码问题(指定响应体返回类型和编码)
@ResponseBody
使返回值不经过视图解析器,直接返回字符串
ObjectMapper
jackson所带的json处理类
1 2 3 4 5 6 7 8 9 10 11 12 13 @Controller public class UserController { @RequestMapping(value="/j1", produces = "application/json;charset=utf-8") @ResponseBody public String json1 (Model model) throws JsonProcessingException { ObjectMapper objectMapper = new ObjectMapper (); User user = new User ("Bayyy" , 18 , "男" ); String s = objectMapper.writeValueAsString(user); return s; } }
测试结果:
5.3.2 乱码解决 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <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 >
5.3.3 @RestController 统一返回JSON
在类上直接使用 @RestController ,所有的方法都只会返回 json 字符串
:key: 前后端分离开发中,一般都使用 @RestController
1 2 3 4 5 6 7 8 9 10 11 12 13 @RestController public class UserController { @RequestMapping("/j1") public String json1 (Model model) throws JsonProcessingException { ObjectMapper objectMapper = new ObjectMapper (); User user = new User ("Bayyy" , 18 , "男" ); String s = objectMapper.writeValueAsString(user); return s; } }
5.3.4 集合输出 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 @RequestMapping("/j2") public String json2 () throws JsonProcessingException { ObjectMapper mapper = new ObjectMapper (); List<User> userList = new ArrayList <User>(); User user1 = new User ("Bayyy1" , 18 , "男" ); User user2 = new User ("Bayyy2" , 18 , "男" ); User user3 = new User ("Bayyy3" , 18 , "男" ); User user4 = new User ("Bayyy4" , 18 , "男" ); userList.add(user1); userList.add(user2); userList.add(user3); userList.add(user4); String s = mapper.writeValueAsString(userList); return s; }
测试结果:
5.3.5 时间输出 1)基本使用 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 @RequestMapping("/j3") public String json3 () throws JsonProcessingException { return new ObjectMapper ().writeValueAsString(new Date ()); } @RequestMapping("/j3") public String json3 () throws JsonProcessingException { Date date = new Date (); SimpleDateFormat sdf = new SimpleDateFormat ("yyyy-MM-dd HH:mm:ss" ); return new ObjectMapper ().writeValueAsString(sdf.format(date)); } @RequestMapping("/j3") public String json3 () throws JsonProcessingException { ObjectMapper mapper = new ObjectMapper (); mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false ); SimpleDateFormat sdf = new SimpleDateFormat ("yyyy-MM-dd HH:mm:ss" ); mapper.setDateFormat(sdf); Date date = new Date (); return mapper.writeValueAsString(date); }
测试结果:
2)抽象工具类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public class JsonUtils { public static String getJson (Object object) { return getJson(object,"yyyy-MM-dd HH:mm:ss" ); } public static String getJson (Object object,String dateFormat) { ObjectMapper mapper = new ObjectMapper (); mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false ); SimpleDateFormat sdf = new SimpleDateFormat (dateFormat); mapper.setDateFormat(sdf); try { return mapper.writeValueAsString(object); } catch (JsonProcessingException e) { e.printStackTrace(); } return null ; } }
使用
1 2 3 4 5 6 7 @RequestMapping("/j4") public String json4 () throws JsonProcessingException { Date date = new Date (); String json = JsonUtils.getJson(date); return json; }
5.4 FastJson
fastjson.jar是阿里开发的一款专门用于Java开发的包,可以方便的实现json对象与JavaBean对象的转换,实现JavaBean对象与json字符串的转换,实现json对象与json字符串的转换。实现json的转换方法很多,最后的实现结果都是一样的。
三个主要的类
JSONObject 代表 json 对象
JSONObject实现了Map接口, 猜想 JSONObject底层操作是由Map实现的。
JSONObject对应json对象,通过各种形式的get()方法可以获取json对象中的数据,也可利用诸如size(),isEmpty()等方法获取”键:值”对的个数和判断是否为空。其本质是通过实现Map接口并调用接口中的方法完成的。
JSONArray 代表 json 对象数组
JSON代表 JSONObject和JSONArray的转化
JSON类源码分析与使用
仔细观察这些方法,主要是实现json对象,json对象数组,javabean对象,json字符串之间的相互转化。
5.4.1 导包 1 2 3 4 5 6 <dependency > <groupId > com.alibaba</groupId > <artifactId > fastjson</artifactId > <version > 2.0.37</version > </dependency >
5.4.2 测试 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 @RequestMapping("/j5") public String json5 () throws JsonProcessingException { ObjectMapper mapper = new ObjectMapper (); List<User> userList = new ArrayList <User>(); User user1 = new User ("Bayyy1" , 18 , "男" ); User user2 = new User ("Bayyy2" , 18 , "男" ); User user3 = new User ("Bayyy3" , 18 , "男" ); User user4 = new User ("Bayyy4" , 18 , "男" ); userList.add(user1); userList.add(user2); userList.add(user3); userList.add(user4); String s = JSON.toJSONString(userList); return s; }
5.4.3 更多使用 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 System.out.println("*******Java对象 转 JSON字符串*******" ); String str1 = JSON.toJSONString(userList);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);
Java对象 转 JSON字符串
String str = JSON.toJSONString(userList);
JSON字符串 转 Java对象
User user = JSON.parseObject(str, User.class);
Java对象 转 JSON对象
JSONObject jsonObject = (JSONObject) JSON.toJSON(user)
JSON对象 转 Java对象
User user = JSON.toJavaObject(jsonObject, User.class);
6. SSM整合
此时的环境配置
JAVA 1.8.0_361
mysql 5.7.19
Tomcat 9.0.76
Maven 3.9.2
6.1 数据库搭建 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 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 ,'从进门到进牢' );
6.2 基本环境搭建 6.2.1 Maven项目 6.2.2 pom依赖 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 <dependencies > <dependency > <groupId > junit</groupId > <artifactId > junit</artifactId > <version > 3.8.1</version > <scope > test</scope > </dependency > <dependency > <groupId > javax.servlet</groupId > <artifactId > javax.servlet-api</artifactId > <version > 4.0.1</version > </dependency > <dependency > <groupId > javax.servlet.jsp</groupId > <artifactId > jsp-api</artifactId > <version > 2.2</version > </dependency > <dependency > <groupId > javax.servlet.jsp.jstl</groupId > <artifactId > jstl-api</artifactId > <version > 1.2</version > </dependency > <dependency > <groupId > taglibs</groupId > <artifactId > standard</artifactId > <version > 1.1.2</version > </dependency > <dependency > <groupId > mysql</groupId > <artifactId > mysql-connector-java</artifactId > <version > 8.0.19</version > </dependency > <dependency > <groupId > c3p0</groupId > <artifactId > c3p0</artifactId > <version > 0.9.1.2</version > </dependency > <dependency > <groupId > org.mybatis</groupId > <artifactId > mybatis</artifactId > <version > 3.5.13</version > </dependency > <dependency > <groupId > org.mybatis</groupId > <artifactId > mybatis-spring</artifactId > <version > 2.0.7</version > </dependency > <dependency > <groupId > org.springframework</groupId > <artifactId > spring-webmvc</artifactId > <version > 5.3.24</version > </dependency > <dependency > <groupId > org.springframework</groupId > <artifactId > spring-jdbc</artifactId > <version > 5.3.24</version > </dependency > <dependency > <groupId > org.aspectj</groupId > <artifactId > aspectjweaver</artifactId > <version > 1.9.19</version > </dependency > <dependency > <groupId > org.projectlombok</groupId > <artifactId > lombok</artifactId > <version > 1.18.28</version > </dependency > </dependencies > <build > <resources > <resource > <directory > src/main/java</directory > <includes > <include > **/*.xml</include > <include > **/*.properties</include > </includes > </resource > <resource > <directory > src/main/resources</directory > <includes > <include > **/*.xml</include > <include > **/*.properties</include > </includes > </resource > </resources > <finalName > ssmbuild</finalName > </build >
6.2.3 结构和配置架构
pojo
dao
service
controller
mybatis-config.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "https://mybatis.org/dtd/mybatis-3-config.dtd" > <configuration > <settings > <setting name ="mapUnderscoreToCamelCase" value ="true" /> </settings > <typeAliases > <package name ="com.bayyy.pojo" /> </typeAliases > </configuration >
applicationContext.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 <?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:aop ="http://www.springframework.org/schema/aop" xsi:schemaLocation ="http://www.springframework.org/schema/beans https://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/aop https://www.springframework.org/schema/aop/spring-aop.xsd" > <context:component-scan base-package ="com.bayyy" /> <context:annotation-config /> <aop:aspectj-autoproxy /> <import resource ="spring-dao.xml" /> </beans >
6.2.4 MyBatis层编写
db.properties
1 2 3 4 driver =com.mysql.cj.jdbc.Driver url =jdbc:mysql://localhost:3306/mybatis?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC username =root password =123456
mybatis-config.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "https://mybatis.org/dtd/mybatis-3-config.dtd" > <configuration > <settings > <setting name ="mapUnderscoreToCamelCase" value ="true" /> </settings > <typeAliases > <package name ="com.bayyy.pojo" /> </typeAliases > <mappers > <mapper class ="com.bayyy.dao.BookMapper" /> </mappers > </configuration >
POJO
1 2 3 4 5 6 7 8 9 @Data @NoArgsConstructor @AllArgsConstructor public class Books { private int bookID; private String bookName; private int bookCounts; private String detail; }
Mapper接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public interface BookMapper { int addBook (Books books) ; int deleteBookByID (@Param("bookID") int id) ; int updateBook (Books books) ; Books queryBookByID (@Param("bookID") int id) ; List<Books> queryAllBook () ; }
Mapper.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "https://mybatis.org/dtd/mybatis-3-mapper.dtd" > <mapper namespace ="com.bayyy.dao.BookMapper" > <insert id ="addBook" parameterType ="books" > insert into books (bookName,bookCounts,detail) values(#{bookName},#{bookCounts},#{detail}) </insert > <delete id ="deleteBookById" parameterType ="int" > delete from books where bookID=#{bookID} </delete > <update id ="updateBook" parameterType ="books" > update books set bookName=#{bookName},bookCounts=#{bookCounts},detail=#{detail} where bookID=#{bookID} </update > <select id ="queryBookById" parameterType ="int" resultType ="books" > select * from books where bookID=#{bookID} </select > <select id ="queryAllBook" resultType ="books" > select * from books </select > </mapper >
Service接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public interface BookService { int addBook (Books books) ; int deleteBookByID (int id) ; int updateBook (Books books) ; Books queryBookByID (int id) ; List<Books> queryAllBook () ; }
Service实现类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 public class BookServiceImpl implements BookService { private BookMapper bookMapper; public void setBookMapper (BookMapper bookMapper) { this .bookMapper = bookMapper; } @Override public int addBook (Books books) { return this .bookMapper.addBook(books); } @Override public int deleteBookByID (int id) { return this .bookMapper.deleteBookByID(id); } @Override public int updateBook (Books books) { return this .bookMapper.updateBook(books); } @Override public Books queryBookByID (int id) { return this .bookMapper.queryBookByID(id); } @Override public List<Books> queryAllBook () { return this .bookMapper.queryAllBook(); } }
6.2.5 Spring层 配置
spring-dao.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 <?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 https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd" > <context:property-placeholder location ="classpath:db.properties" /> <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}" /> <property name ="maxPoolSize" value ="30" /> <property name ="minPoolSize" value ="10" /> <property name ="autoCommitOnClose" value ="false" /> <property name ="checkoutTimeout" value ="10000" /> <property name ="acquireRetryAttempts" value ="2" /> </bean > <bean id ="sqlSessionFactory" class ="org.mybatis.spring.SqlSessionFactoryBean" > <property name ="dataSource" ref ="datasource" /> <property name ="configLocation" value ="classpath:mybatis-config.xml" /> </bean > <bean class ="org.mybatis.spring.mapper.MapperScannerConfigurer" > <property name ="sqlSessionFactoryBeanName" value ="sqlSessionFactory" /> <property name ="basePackage" value ="com.bayyy.dao" /> </bean > </beans >
spring-service.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 <?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:tx ="http://www.springframework.org/schema/tx" xsi:schemaLocation ="http://www.springframework.org/schema/beans https://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/tx http://www.springframework.org/schema/tx/spring-tx.xsd" > <context:component-scan base-package ="com.bayyy.service" /> <bean id ="BookServiceImpl" class ="com.bayyy.service.BookServiceImpl" > <property name ="bookMapper" ref ="bookMapper" /> </bean > <bean id ="transactionManager" class ="org.springframework.jdbc.datasource.DataSourceTransactionManager" > <property name ="dataSource" ref ="datasource" /> </bean > <tx:advice id ="txAdvice" transaction-manager ="transactionManager" > <tx:attributes > <tx:method name ="add*" propagation ="REQUIRED" /> <tx:method name ="delete*" propagation ="REQUIRED" /> <tx:method name ="update*" propagation ="REQUIRED" /> <tx:method name ="find*" propagation ="SUPPORTS" read-only ="true" /> <tx:method name ="*" propagation ="SUPPORTS" read-only ="true" /> </tx:attributes > </tx:advice > </beans >
6.2.6 SpringMVC层 配置
web.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 <?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:applicationContext.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 > <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 > <session-config > <session-timeout > 30</session-timeout > </session-config > </web-app >
spring-mvc.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 <?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" > <mvc:annotation-driven /> <mvc:default-servlet-handler /> <context:component-scan base-package ="com.bayyy.controller" /> <bean class ="org.springframework.web.servlet.view.InternalResourceViewResolver" id ="internalResourceViewResolver" > <property name ="prefix" value ="/WEB-INF/jsp/" /> <property name ="suffix" value =".jsp" /> </bean > </beans >
applicationContext.xml整合
1 2 3 4 5 6 7 8 9 10 11 <?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 https://www.springframework.org/schema/beans/spring-beans.xsd" > <import resource ="classpath: spring-dao.xml" /> <import resource ="classpath: spring-service.xml" /> <import resource ="classpath:spring-mvc.xml" /> </beans >
6.2.7 Controller和视图层 1)BookController-allBook 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 @Controller @RequestMapping("/book") public class BookController { @Autowired @Qualifier("bookServiceImpl") private BookService bookService; @RequestMapping("/allBook") public String list (Model model) { List<Books> books = bookService.queryAllBook(); model.addAttribute("list" , books); return "allBook" ; } }
2)index.jsp 及美化 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 <%@ 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>
3)allBook.jsp 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 <%@ 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> <%-- 书籍从数据库中获取, 从list中遍历: forEach --%> <tbody> <c:forEach var ="book" items="${list}" > <tr> <td>${book.bookID}</td> <td>${book.bookName}</td> <td>${book.bookCounts}</td> <td>${book.detail}</td> <td> <a href="${pageContext.request.contextPath}/book/toUpdateBook?id=${book.bookID}" >更改</a> | <a href="${pageContext.request.contextPath}/book/del/${book.bookID}" >删除</a> </td> </tr> </c:forEach> </tbody> </table> </div> </div> </div>
4)BookController-add/del 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 @RequestMapping("/toAddBook") public String toAddBook () { return "toAddBook" ; } @RequestMapping("/addBook") public String addBook (Books books) { bookService.addBook(books); return "redirect:/book/allBook" ; } @RequestMapping("/toUpdateBook/{bookId}") public String toUpdateBook (@PathVariable("bookId") int bookId, Model model) { Books book = bookService.queryBookByID(bookId); System.out.println(book); model.addAttribute("book" , book); return "toUpdateBook" ; } @RequestMapping("/updateBook") public String updateBook (Books books) { bookService.updateBook(books); return "redirect:/book/allBook" ; } @RequestMapping("/del/{bookId}") public String deleteBookById (@PathVariable("bookId") int bookId) { bookService.deleteBookByID(bookId); return "redirect:/book/allBook" ; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 <%@ 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" > <div class="form-group" > <label for ="bookName" >书籍名称</label> <input type="text" class="form-control" name="bookName" id="bookName" placeholder="请输入书籍名称" required> </div> <div class="form-group" > <label for ="bookCounts" >书籍数量</label> <input type="text" class="form-control" name="bookCounts" id="bookCounts" placeholder="请输入书籍数量" required> </div> <div class="form-group" > <label for ="detail" >书籍描述</label> <input type="text" class="form-control" name="detail" id="detail" placeholder="请输入书籍描述" required> </div> <input type="submit" value="添加" > </form> </div>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 <%@ 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.bookID}" /> 书籍名称:<input type="text" name="bookName" value="${book.bookName}" /> 书籍数量:<input type="text" name="bookCounts" value="${book.bookCounts}" /> 书籍详情:<input type="text" name="detail" value="${book.detail}" /> <input type="submit" value="修改" /> </form> </div>
5)新增查询功能 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 @RequestMapping("/queryBook") public String queryBookByName (@Param("queryBookName") String queryBookName, Model model) { if (queryBookName.equals("" )) { model.addAttribute("error" , "未查到" ); return "allBook" ; } Books books = bookService.queryBookByName(queryBookName); ArrayList<Books> list = new ArrayList <Books>(); list.add(books); if (books == null ) { list = (ArrayList<Books>) bookService.queryAllBook(); model.addAttribute("error" , "未查到" ); } model.addAttribute("list" , list); return "allBook" ; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <div class="row" > <div class="col-md-4 column" > <a class="btn btn-primary" href="${pageContext.request.contextPath}/book/toAddBook" >新增</a> </div> <div class="col-md-4 column" > <a class="btn btn-primary" href="${pageContext.request.contextPath}/book/allBook" >显示所有书籍</a> </div> <div class="col-md-4 column" > <%--查询书籍--%> <form action="${pageContext.request.contextPath}/book/queryBook" method="post" class="form-inline" > <span class="glyphicon glyphicon-pencil" aria-hidden="true" style="color: red;font-weight: bold" >${error}</span> <input type="text" name="queryBookName" class="form-control" placeholder="请输入要查询的书籍名称" > <input type="submit" value="查询" class="btn btn-primary" > </form> </div> </div>
7. Ajax 7.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用户界面。
7.2 伪造Ajax 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 <!DOCTYPE html > <html lang ="en" > <head > <meta charset ="UTF-8" > <title > iframe测试体验页面无刷新</title > <script > function go ( ) { const url = document .getElementById ("url" ).value ; document .getElementById ("iframe1" ).src =url; } </script > </head > <body > <div > <p > 请输入地址</p > <p > <input type ="text" id ="url" value ="https://www.bilibili.com/" > <input type ="submit" value ="提交" onclick ="go()" > </p > </div > <div > <iframe id ="iframe1" style ="width: 100%; height: 500px" > </iframe > </div > </body > </html >
7.3 jQuery.ajax
Ajax的核心和本质就是XMLHttpRequest对象(XHR)。XHR为向服务器发送请求和解析服务器响应提供了接口。能够以异步方式从服务器获取新数据
通过 jQuery AJAX 方法,能够使用 HTTP Get 和 HTTP Post 从远程服务器上请求文本、HTML、XML 或 JSON – 同时您能够把这些外部数据直接载入网页的被选元素中
7.3.1 语法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 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 将自动替换 ? 为正确的函数名,以执行回调函数
7.3.2 使用 1)配置 1 2 3 <context:component-scan base-package ="com.bayyy.controller" /> <mvc:default-servlet-handler /> <mvc:annotation-driven />
2)AjaxController 1 2 3 4 5 6 7 8 9 @RequestMapping("/a1") public void a1 (String name, HttpServletResponse response) throws IOException { System.out.println("a1:param: " + name); if ("bayyy" .equals(name)) { response.getWriter().print("true" ); } else { response.getWriter().print("false" ); } }
3)编写index.jsp测试 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> <script src="${pageContext.request.contextPath}/statics/js/jquery-3.7.0.js" ></script> <script> function a () { $.post({ url: "${pageContext.request.contextPath}/a1" , data: {"name" : $("#username" ).val()}, success: function (data, status) { alert("data=>" +data+" status=>" +status); } }) } </script> </head> <body> <%--失去焦点的时候,发起请求到后台--%> 用户名:<input type="text" id="username" onblur="a()" > </body> </html>
测试结果:
7.3.2 返回显示表单+html 1 2 3 4 5 6 7 8 @RequestMapping("/a2") public List<User> a2 () { List<User> users = new ArrayList <User>(); users.add(new User ("bayyy" , 18 , "男" )); users.add(new User ("cdn" , 18 , "女" )); users.add(new User ("bayyy" , 18 , "男" )); return users; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> <script src="${pageContext.request.contextPath}/statics/js/jquery-3.7.0.js" ></script> <script> $(function () { $("#btn" ).click(function () { $.post("${pageContext.request.contextPath}/a2" , function (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].sex + "</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>
测试结果:
7.3.3 注册提示效果 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> <script src="${pageContext.request.contextPath}/statics/js/jquery-3.7.0.js" ></script> <script> function a1 () { $.post({ url:"${pageContext.request.contextPath}/a3" , data:{"name" :$("#name" ).val()}, success:function (data) { if (data.toString()==="ok" ) { $("#userInfo" ).css("color" ,"green" ); } else { $("#userInfo" ).css("color" ,"red" ); console.log(data); } $("#userInfo" ).html(data); } }) } function a2 () { $.post({ url:"${pageContext.request.contextPath}/a3" , 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="a1()" > <span id="userInfo" ></span> </p> <p> 密码:<input type="text" id="pwd" onblur="a2()" > <span id="pwdInfo" ></span> </p> </body> </html>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 @RequestMapping("/a3") public String a3 (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; }
测试结果:
8. 拦截器 8.1 概述 SpringMVC的处理器拦截器类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理。开发者可以自己定义一些拦截器来实现特定的功能。
过滤器与拦截器的区别: 拦截器是AOP思想的具体应用。
过滤器
servlet规范中的一部分,任何java web工程都可以使用
在url-pattern中配置了/*之后,可以对所有要访问的资源进行拦截
拦截器
拦截器是SpringMVC框架自己的,只有使用了SpringMVC框架的工程才能使用
拦截器只会拦截访问的控制器方法 , 如果访问的是jsp/html/css/image/js是不会进行拦截的
8.2 自定义拦截器
实现 HandlerInterceptor 接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public class MyInterceptor implements HandlerInterceptor { @Override public boolean preHandle (HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("处理前" ); return true ; } @Override public void postHandle (HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("处理后" ); } @Override public void afterCompletion (HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("清理" ); } }
8.3 用户登录的实现
1、有一个登陆页面,需要写一个controller访问页面。
2、登陆页面有一提交表单的动作。需要在controller中处理。判断用户名密码是否正确。如果正确,向session中写入用户信息。返回登陆成功。
3、拦截用户请求,判断用户是否登陆。如果用户已经登陆。放行, 如果用户未登陆,跳转到登陆页面
1 2 3 4 5 6 7 8 9 10 11 12 13 14 <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> <h1>登录页面</h1> <form action="${pageContext.request.contextPath}/user/login" method="get" > 用户名:<input type="text" name="username" ><br> 密码:<input type="password" name="password" ><br> <input type="submit" value="登录" > </form> </body> </html>
1 2 3 4 5 6 7 8 9 10 11 <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> <h1>首页</h1> <span>${username}</span> <a href="${pageContext.request.contextPath}/user/logout" >注销</a> </body> </html>
1 2 3 4 5 6 7 8 9 10 <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> <h1><a href="${pageContext.request.contextPath}/user/goLogin" >登录</a></h1> <h1><a href="${pageContext.request.contextPath}/user/main" >首页</a></h1> </body> </html>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 @Controller @RequestMapping("/user") public class LoginController { @RequestMapping("/login") public String login (@RequestParam("username") String name, @RequestParam("password") String pwd, HttpSession session) { session.setAttribute("user" , name); System.out.println(session.getAttribute("user" )); return "main" ; } @RequestMapping("/goLogin") public String goLogin (HttpSession session) { return "login" ; } @RequestMapping("/logout") public String logout (HttpSession session) { session.removeAttribute("user" ); return "login" ; } @RequestMapping("/main") public String main () { return "main" ; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public class LoginInterceptor implements HandlerInterceptor { @Override public boolean preHandle (HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { HttpSession session = request.getSession(); if (request.getRequestURI().contains("ogin" )){ return true ; } if (session.getAttribute("user" ) != null ) { return true ; } request.getRequestDispatcher("/WEB-INF/jsp/login.jsp" ).forward(request, response); return false ; } }
9. 文件上传和下载 9.1 准备工作 9.1.1 前端
:key: enctype
application/x-www=form-urlencoded:默认方式,只处理表单域中的 value 属性值,采用这种编码方式的表单会将表单域中的值处理成 URL 编码方式。
multipart/form-data:这种编码方式会以二进制流的方式来处理表单数据,这种编码方式会把文件域指定文件的内容也封装到请求参数中,不会对字符编码。
text/plain:除了把空格转换为 “+” 号外,其他字符都不做编码处理,这种方式适用直接通过表单发送邮件。
method=post
enctype=multipart/form-data
1 2 3 4 <form action="" enctype="multipart/form-data" method="post" > <input type="file" name="file" /> <input type="submit" > </form>
9.1.2 导包 1 2 3 4 5 6 <!-- https: <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.5 </version> </dependency>
9.2 文件上传 9.2.1 前端页面 1 2 3 4 5 6 7 8 9 10 11 12 13 14 <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html > <head > <title > Title</title > </head > <body > <form action ="${pageContext.request.contextPath}/upload2" enctype ="multipart/form-data" method ="post" > <input type ="file" name ="file" /> <input type ="submit" > </form > </body > </html >
9.2.2 Bean
:hotsprings: id
必须是 multipartResolver
1 2 3 4 5 6 7 8 <bean id ="multipartResolver" class ="org.springframework.web.multipart.commons.CommonsMultipartResolver" > <property name ="defaultEncoding" value ="utf-8" /> <property name ="maxUploadSize" value ="10485760" /> <property name ="maxInMemorySize" value ="40960" /> </bean >
9.2.3 两种文件上传的Controller实现方式 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 @RequestMapping("/upload") public String fileUpload (@RequestParam("file") CommonsMultipartFile file, HttpServletRequest request) throws IOException { 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" ; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 @RequestMapping("/upload") public String fileUpload (@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); file.transferTo(new File (realPath +"/" + file.getOriginalFilename())); return "redirect:/index.jsp" ; }
9.3 文件下载
1、设置 response 响应头
2、读取文件 — InputStream
3、写出文件 — OutputStream
4、执行操作
5、关闭流 (先开后关)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 @RequestMapping(value="/download") public String downloads (HttpServletResponse response ,HttpServletRequest request) throws Exception{ String path = request.getServletContext().getRealPath("/upload" ); String fileName = ".jpg" ; response.reset(); 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); InputStream input=new FileInputStream (file); OutputStream out = response.getOutputStream(); byte [] buff =new byte [1024 ]; int index=0 ; while ((index= input.read(buff))!= -1 ){ out.write(buff, 0 , index); out.flush(); } out.close(); input.close(); return null ; }