## SpringMVC教程 ### 一、MVC设计模式简介 MVC 是一种著名的设计模式,特别是在 Web 应用程序领域。模式全都是关于将包含业务数据的模块与显示模块的视图解耦的。 视图(例如,JSP 页面)怎样能够与其模型(例如,包含数据的 JavaBean)解耦? 在模型和视图之间引入重定向层可以解决问题。此重定向层是控制器。控制器将接收请求,执行更新模型的操作,然后通知视图关于模型更改的消息。依赖于模型的状态并且依赖于请求的控制器可以决定要显示哪个视图。 Spring MVC是Spring Framwork的一部分,是基于Java实现的轻量级Web框架。 Spring 的 Web MVC 模块是围绕 DispatcherServlet 而设计的。DispatcherServlet 给处理程序分派请求,执行视图解析。 springmvc的核心控制器,所有的请求到来后,首先经过的DispatcherServlet 。 ### 二、使用XML配置SpringMVC的环境搭建 #### 2.1 创建maven项目,引入依赖 ~~~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.3.8</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>4.0.1</version> <scope>provided</scope> </dependency> <dependency> <groupId>javax.annotation</groupId> <artifactId>javax.annotation-api</artifactId> <version>1.3.2</version> </dependency> <!-- spring 操作jdbc--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.3.8</version> </dependency> <!--AOP相关--> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.7.M3</version> </dependency> <!--jsp的依赖--> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>jsp-api</artifactId> <version>2.2</version> </dependency> <!--jstl标签的依赖--> <dependency> <groupId>javax.servlet.jsp.jstl</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> </dependencies> ~~~ #### 2.2 把maven项目添加了web模块 步骤:点击项目,右键,add framework support ,选择 webapplication打对勾 #### 2.3 配置springmvc.xml核心配置文件 ~~~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:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd"> </beans> ~~~ #### 2.4 编写web.xml文件,配置前端核心控制器 ~~~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"> <!--配置SpringMVC的前端核心控制器--> <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.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> ~~~ **关于DispatcherServlet的配置信息** ~~~xml <servlet-mapping> <servlet-name>springmvc</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <!-- <url-pattern>/</url-pattern> 里面的 / 代表的意思就是除了 jsp的页面请求放行之外,要拦截所有的请求 ,因为springmvc默认的模板引擎是jsp --> ~~~ 1 #### 2.5 创建Controller,实现Controller接口 重写handleRequest ~~~java package cn.hxzy.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 UserController implements Controller { public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { System.out.println("hello,springmvc"); return null; } } ~~~ #### 2.6 编写springmvc.xml配置信息,添加视图解析器 通过BeanNameUrlHandlerMapping的方式完成请求与Controller之间的映射关系 ~~~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:mvc="http://www.springframework.org/schema/mvc" xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd"> <bean name="/user" class="cn.hxzy.controller.UserController"/> <!--视图解析器--> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/jsp/" /> <property name="suffix" value=".jsp"/> <!--/WEB-INF/jsp/index.jsp--> </bean> </beans> ~~~ #### 2.7、ModelAndView的使用 Model模型数据,View是返回的视图名称 ~~~java package cn.hxzy.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 IndexController implements Controller { public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { System.out.println("hello,这是首页!"); ModelAndView mad=new ModelAndView();//模型和视图对象 mad.addObject("message","hello,这是首页!"); mad.setViewName("index"); //逻辑视图名 return mad; } } ~~~ #### 2.8 lib目录添加jar包 配置Artifacts实例,添加lib目录,把maven项目的jar包添加到lib目录下。 #### 2.9 配置tomcat 进行测试 #### 2.10 SpringMVC执行流程图 ![1](1.png) ### 三、使用注解形式配置SpringMVC的开发环境 #### 1、在核心配置文件中添加注解 ~~~~xml <context:component-scan base-package="cn.hxzy.controller"/> <mvc:annotation-driven/> ~~~~ #### 2、在Controller类上添加@Controller注解 #### 3、在方法上添加@RequestMapping注解 #### 4、@ResponseBody注解 #### 5、参数入参 ~~~java //一般会在handle方法的参数上标注@RequestParam参数,也可以直接指定名字,如果指定了名字的话,入参的参数必须为指定的名字。 @RequestMapping("index") public String getIndex(@RequestParam("uname") String userName, @RequestParam("age") Integer age) { } //@RequestParam("uname")是可以缺省的。 //有些时候某些接口的参数不需要全部都指定的时候,就可以使用@RequestParam来进行设置 @RequestParam("uname") String userName, @RequestParam(value = "age",required = false) ~~~ #### 6、@RequestMapping的使用 ~~~java @GetMapping //只能接收get请求 @PostMapping //只能接收post请求 @RequestMapping //标注在controller ~~~ #### 7、跨域的注解 ```java @CrossOrigin //跨域的注解 ``` #### 8、@RequestBody注解 **注意:前提必须:使用@PostMapping注解接收** 直接拿对象进行映射:传统的web表单提交,如果要使用异步(axios)提交,必须加一个注解。 HTTP状态 415 - 不支持的媒体类型 遇到400问题,最大几率是出现了数据类型不一致的问题,简单来说是Controller层不用正确读取你发送请求附带的参数 从请求的body区域获取数据 如果使用传统的表单方式去提交,对象可以直接入参,无需添加@RequestBody注解 springmvc-controller接收配置 ~~~java @ResponseBody @RequestMapping(value = "login") public String login(@RequestBody User user) { System.out.println(user); return "123"; } ~~~ @RequestBody注解在参数中只能出现一次 ### 四、JSON的使用 #### 1、JackSon工具的使用 ##### 1.1 导入依赖 ~~~xml <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.13.0</version> </dependency> ~~~ ##### 1.2 项目中应用 #### 2、解决中文乱码情况 ##### 2.1自定义过滤器 ~~~java package cn.hxzy.filter; import javax.servlet.*; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; public class CharacterEncodingFilter implements Filter { public void init(FilterConfig filterConfig) throws ServletException { } public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { HttpServletRequest request=(HttpServletRequest) servletRequest; HttpServletResponse response=(HttpServletResponse)servletResponse; request.setCharacterEncoding("utf-8"); response.setContentType("text/html;charset=utf-8"); filterChain.doFilter(request,response); } public void destroy() { } } ~~~ ##### 2.2 内置的过滤器,在web.xml中进行配置 ~~~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> ~~~ 注意,使用web.xml配置Filter时,必须放在配置文件的最前面 因为springmvc的默认消息转换器的优先级高与filter ##### 2.3 设置springmvc的关于字符串处理的消息转换器 ~~~xml <!--解决json 乱码配置--> <mvc:annotation-driven> <mvc:message-converters register-defaults="true"> <!--springmvc的关于字符串处理的消息转换器--> <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> ~~~ #### 3、格式化double类型的数据,保留两位小数 1. 定义一个类,继承JsonSerializer类,重写里面的serialize方法,定义格式化规则 ~~~java package cn.hxzy.config; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.databind.JsonSerializer; import com.fasterxml.jackson.databind.SerializerProvider; import java.io.IOException; import java.text.DecimalFormat; public class DoubleFormat extends JsonSerializer<Double> { private DecimalFormat df=new DecimalFormat("##.00"); public void serialize(Double aDouble, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException { if(aDouble!=null){ jsonGenerator.writeString(df.format(aDouble)); } } } ~~~ 2.在实体类的属性上添加注解,引入自己定义的规则 ~~~java @JsonSerialize(using = DoubleFormat.class) private Double userMoney; ~~~ #### 4、使用Jackson完成在Controller里直接返回对象与集合类型的数据 示例: java代码 @RestController 是@Controller与@ResponseBody的合体写法 ~~~java package cn.hxzy.controller; import cn.hxzy.pojo.User; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.*; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; @RequestMapping("/user") @RestController public class UserController { @RequestMapping("userList") public List<User> getUserList(){ User u1 = new User(1, "李旭东", 20,100.02003,new Date()); User u2 = new User(2, "刘德华", 21,100.02003,new Date()); User u3 = new User(3, "张三", 22,100.02003,new Date()); List<User> list=new ArrayList<User>(); list.add(u1); list.add(u2); list.add(u3); return list; } } ~~~ html部分 ~~~html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>用户信息</title> </head> <body></table> <input type="button" value="点击获取数据" id="btn"> </body> <script src="js/jquery-3.6.0.js" type="text/javascript" charset="UTF-8"></script> <script type="text/javascript"> $("#btn").click(function () { getUserInfo(); }); function getUserInfo() { $("#userList").empty(); $.ajax({ url:"/user/userList", type:"get", dataType:"json", success:function (rs) { var $rs=$(rs); $("#userList").append("<tr> <th>编号</th><th>姓名</th> <th>年龄</th> <th>生日</th> <th>余额</th> </tr>"); $rs.each(function (index,item) { console.log(item) $("#userList").append("<tr><td>"+this.userId+"</td><td>"+this.userName+"</td><td>"+this.userAge+"</td><td>"+this.userBirthday+"</td><td>"+this.userMoney+"</td></tr>"); }) } }) } </script> </html> ~~~ #### 5.跨域的配置 跨域并不会阻止请求的发出,也不会阻止请求的接收,跨域是浏览器为了保护当前页面,你的请求得到了响应,浏览器不会把响应的数据交给页面上的回调,取而代之的是去提示你这是一个跨域数据。 开放单个IP ~~~java package com.hxzy.news.filter; import javax.servlet.*; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; public class CrossFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest)servletRequest; HttpServletResponse response = (HttpServletResponse)servletResponse; // 允许跨域的地址*表示所有 response.setHeader("Access-Control-Allow-Origin", "*"); // 表示是否允许发送Cookie response.setHeader("Access-Control-Allow-Credentials", "true"); // 允许跨域的方法 response.setHeader("Access-Control-Allow-Methods", "POST,GET,OPTIONS,DELETE"); // 预检请求的有效期,OPTIONS请求就是想服务端进行探测支持的方法 response.setHeader("Access-Control-Max-Age", "3600"); // 跨域时允许的请求头字段 response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept,Token,tokenzsk,tokenzsk1"); // 检测时直接返回 if ("OPTIONS".equals(request.getMethod())) { response.setStatus(HttpServletResponse.SC_NO_CONTENT); return; } filterChain.doFilter(servletRequest, servletResponse); } @Override public void destroy() { } } ~~~ 多个IP的配置 ~~~java package cn.hxzy.myschool.filter; import javax.servlet.*; import javax.servlet.annotation.WebFilter; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; @WebFilter("/*") public class CorsFilter implements Filter { public void init(FilterConfig filterConfig) throws ServletException { } public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) servletRequest; HttpServletResponse response = (HttpServletResponse) servletResponse; // IP地址列表 String[] arr = {"http://192.168.8.51:8848", "http://192.168.8.74:8848"}; Set<String> set=new HashSet<String>(Arrays.asList(arr)); String originHeader = request.getHeader("Origin"); if(set.contains(originHeader)){ response.setHeader("Access-Control-Allow-Origin",originHeader); // 表示是否允许发送Cookie response.setHeader("Access-Control-Allow-Credentials", "true"); // 允许跨域的方法 response.setHeader("Access-Control-Allow-Methods", "POST,GET,OPTIONS,DELETE,PUT"); // 预检请求的有效期,OPTIONS请求就是想服务端进行探测支持的方法 response.setHeader("Access-Control-Max-Age", "3600"); // 跨域时允许的请求头字段 response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept,Token"); } // 检测时直接返回 if ("OPTIONS".equals(request.getMethod())) { response.setStatus(HttpServletResponse.SC_NO_CONTENT); return; } filterChain.doFilter(servletRequest, servletResponse); } public void destroy() { } } ~~~ 注解实现 ~~~java //@CrossOrigin(value = "http://192.168.8.74:8848") @CrossOrigin(value = {"http://192.168.8.51:8848"},allowCredentials = "true") ~~~ 前端设置ajax ~~~js xhrFields: {withCredentials: true}, crossDomain:true, ~~~ ### 5、使用Servlet API对象作为入参 ~~~java package cn.hxzy.controller; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; @Controller public class IndexController { @RequestMapping("go") public String go() { return "user"; } @RequestMapping("toLogin") public String login(HttpServletResponse response, HttpServletRequest request, Model model) { HttpSession session = request.getSession(); session.setAttribute("userName", "zhangsan"); model.addAttribute("session", session); return "user"; } } ~~~ 说明:如果需要用到Servlet 对象,则只需要在方法的参数中进行设置即可使用。 ### 6、REST风格 * 请求方式的配置 ~~~java @RequestMapping(value = "index",method= RequestMethod.POST) /*RequestMethod是一个枚举类型的值,其中包含 GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS, TRACE;*/ <a href="/user">跳转到</a> 超链接是get请求。 ~~~ Representational State Transfer,表述性状态转移,是一种软件架构风格 Spring MVC提供对REST风格的支持 优点:简洁,高效,安全 基于REST构建的API就是`Restful`风格。 #### 1、@PathVariable与@RequestParam 区别 相同点:都是用于从request中接收请求的,两个都可以接收参数 不同点:@RequestParam 是从request里面拿取值,而 @PathVariable 是从一个URI模板里面来填充 统一接口。Restful风格的数据元操作CRUD(create,read,update,delete)分别对应HTTP方法: GET用来获取资源,POST用来新建资源(也可以用于更新资源), PUT用来更新资源,DELETE用来删除资源,这样就统一了数据操作的接口 如果是查询请求,Controller使用@GetMapping,如果是新增操作,Controller使用@PostMapping,如果是更新操作,Controller使用@PutMapping ,如果是删除操作,Controller使用@DeleteMapping #### 2、配置DELETE、PUT请求 web.xml的设置如下: ~~~xml <filter> <filter-name>HiddenHttpMethodFilter</filter-name> <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class> </filter> <filter-mapping> <filter-name>HiddenHttpMethodFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> ~~~ html的表单设置如下: ~~~html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>注册</title> </head> <body> <form action="/del" method="post"> 编号:<input type="text" name="uid"/><br/> <input type="hidden" name="_method" value="DELETE" > <!--<input type="hidden" name="_method" value="PUT" >--> <input type="submit" value="注册"> </form> </body> </html> ~~~ 406异常说明: 状态码:406,请求头(Request Headers)中看到Accept优先是application/json格式,而响应头(Response Hraders)中却发现返回信息的格式 是“text/html”,前台无法解析,需将结果转换成json格式返回给前台。 ### 7、SSM框架的整合 1、mybatis框架:是数据访问层的解决方案。作用是操作数据库,实现实体与sql语句的映射,底层封装的jdbc。半自动化的ORM框架。(Spring-Templatejdbc)。 2、Spring框架:Spring的核心宗旨:不重复的造轮子,它是一个技术平台,也是一个生态环境。它对现如今所有流行的框架都做了整合。主要使用了IOC依赖注入与AOP的方式进行各种组件的注册与管理。mybatis-spring.jar包是mybatis所做得对spring整合的补丁包。 3、SpringMVC框架:是一个Spring对Servlet的一个封装,经典的Model2的实现,是一个基于模型与视图层的技术框架。 #### 7.1 整合步骤 1、把所有的依赖导入项目 ~~~xml <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>cn.hxzy.ssm</groupId> <artifactId>ssm-demo-01</artifactId> <version>1.0</version> <dependencies> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.7</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.29</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>2.0.6</version> </dependency> <!--阿里巴巴的数据源连接池--> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.10</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.3.8</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>4.0.1</version> <scope>provided</scope> </dependency> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>jsp-api</artifactId> <version>2.2</version> </dependency> <dependency> <groupId>javax.annotation</groupId> <artifactId>javax.annotation-api</artifactId> <version>1.3.2</version> </dependency> <!-- spring 操作jdbc--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.3.8</version> </dependency> <!--AOP相关--> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.7.M3</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.20</version> <scope>provided</scope> </dependency> <dependency> <groupId>commons-lang</groupId> <artifactId>commons-lang</artifactId> <version>2.6</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.13.0</version> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> <!--commonsupload上传组件--> <!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload --> <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.4</version> </dependency> </dependencies> </project> ~~~ 2、依次填写各自的配置文件 springmvc-config.xml ~~~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:mvc="http://www.springframework.org/schema/mvc" xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd"> <!--spring 其他配置文件的导入--> <import resource="applicationContext.xml"/> <context:component-scan base-package="cn.hxzy.ticket"/> <mvc:annotation-driven> <mvc:message-converters register-defaults="true"> <!--springmvc的关于字符串处理的消息转换器--> <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> <!--配置静态资源的访问路径, 让携带statics的客户端请求全部在statics目录下去寻找资源--> <mvc:resources location="/statics/" mapping="/statics/**"/> </beans> ~~~ applicationContext.xml ~~~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:mvc="http://www.springframework.org/schema/mvc" xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd"> <!--spring读取properties文件--> <context:property-placeholder location="classpath:druid.properties"/> <!--数据源连接池--> <bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="${druid.driver}"/> <property name="url" value="${druid.url}"/> <property name="username" value="${druid.username}"/> <property name="password" value="${druid.password}"/> <property name="initialSize" value="${druid.pool.init}"/> <property name="minIdle" value="${druid.pool.minIdle}"/> <property name="maxActive" value="${druid.pool.maxActive}"/> <property name="maxWait" value="${druid.pool.maxWait}"/> </bean> <!--Spring注册SqlSessionFactory对象--> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="druidDataSource"/> <property name="configLocation" value="classpath:mybatis-config.xml"/> </bean> <!-- 指定扫描基准包,把包下面面的接口注册成spring容器所管理的接口对象 --> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="cn.hxzy.ticket.dao"/> </bean> <!-- 定义事务管理器--> <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="druidDataSource"/> </bean> <!--启动注解方式的支持--> <tx:annotation-driven transaction-manager="txManager"/> </beans> ~~~ mybatis-config.xml ~~~ ~~~ druid.properties ~~~properties druid.driver=com.mysql.jdbc.Driver druid.url=jdbc:mysql://localhost:3306/news_db?serverTimezone=GMT%2B8&useUnicode=true&useSSL=false&characterEncoding=utf8 druid.username=root druid.password=root druid.pool.init=30 druid.pool.minIdle=30 druid.pool.maxActive=100 druid.pool.maxWait=10000 ~~~ log4j.properties ~~~ 略 ~~~ springmvc.xml ~~~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:mvc="http://www.springframework.org/schema/mvc" xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd"> <!--spring 其他配置文件的导入--> <import resource="applicationContext.xml"/> <context:component-scan base-package="cn.hxzy.ticket"/> <mvc:annotation-driven> <mvc:message-converters register-defaults="true"> <!--springmvc的关于字符串处理的消息转换器--> <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> <!--配置静态资源的访问路径, 让携带statics的客户端请求全部在statics目录下去寻找资源--> <mvc:resources location="/statics/" mapping="/statics/**"/> </beans> ~~~ web.xml ~~~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"> <!--DispatherServlet--> <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> <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-config.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> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>*.html</url-pattern> </servlet-mapping> <filter> <filter-name>HiddenHttpMethodFilter</filter-name> <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class> </filter> <filter-mapping> <filter-name>HiddenHttpMethodFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> </web-app> ~~~ 3、创建三层结构的项目 #### 7.2 验证码的生成 验证码在web系统中的作用,防止恶意攻击。暴力破解软件。 生成验证码的方法: 1、使用第三方的组件,导入依赖 ~~~xml <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>4.6.6</version> </dependency> ~~~ 2、编写方法实现生成验证码 ~~~java @RequestMapping(value = "getCode",method = RequestMethod.GET) public void getCode(HttpServletRequest request,HttpServletResponse response) throws Exception { //服务器通知浏览器不要缓存 response.setHeader("pragma", "no-cache"); response.setHeader("cache-control", "no-cache"); response.setHeader("expires", "0"); CircleCaptcha captcha = CaptchaUtil.createCircleCaptcha(116, 36, 4, 5); String code = captcha.getCode();//得到code生成的码 HttpSession session = request.getSession(); //每调用一次此方法,就会生成新的code,放入Session一份 session.setAttribute("CHECKCODE", code); ServletOutputStream outputStream = response.getOutputStream(); captcha.write(outputStream); outputStream.close(); } ~~~ 3、编写登录的方法 ~~~java @RequestMapping(value = "/login",method = RequestMethod.POST) public String login(String code,HttpServletRequest request) { System.out.println("code:"+code); //从sesion中获取验证码 HttpSession session = request.getSession(); String checkcode = (String) session.getAttribute("CHECKCODE"); Boolean isCode=true; //标识的布尔变量 if(StringUtils.isNullOrEmpty(code)){ isCode=false; return "验证码为空"; } //equalsIgnoreCase忽略大小写的比较 ABCD===abcd if(!checkcode.equalsIgnoreCase(code)){ isCode=false; return "验证码不正确"; } session.removeAttribute("CHECKCODE");//为了保证验证码只能使用一次 return "success"; } ~~~ 4、前端页面的实现 说明:$("#codeImg").attr("src", "http://localhost:8080/getCode?" + Math.random() * 10); 如果是get请求,第二次请求与第一次请求的路径与参数都一致的话,服务器一般会调用缓存。 ~~~html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>登录</title> </head> <body> 验证码:<input id="code" type="text" name="code"/><img id="codeImg" /> <input type="button" value="登录" id="btn"> </body> <script src="js/jquery-3.6.0.js" type="text/javascript" charset="UTF-8"></script> <script type="text/javascript"> $(function () { getCode(); }) $("#codeImg").click(function () { getCode(); }) function getCode() { $("#codeImg").attr("src", "http://localhost:8080/getCode?" + Math.random() * 10); } $("#btn").click(function () { login(); }); function login() { $.ajax({ url:"/login", data:"code="+$("#code").val(), type:"post", dataType:"text", success:function (rs) { console.log(rs); } }); } </script> </html> ~~~ #### 7.3 md5加密 ~~~java public class MD5Utils { public static String createMd5Str(String pwd) { MD5 md5 = MD5.create(); String pwd1 = md5.digestHex(pwd).substring(2, 22); String str2 = md5.digestHex(pwd1); return str2; } } ~~~ #### 7.4 文件/图片上传 步骤: 1、导入依赖 ~~~xml <!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload --> <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.4</version> </dependency> <!-- https://mvnrepository.com/artifact/commons-io/commons-io --> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.11.0</version> </dependency> ~~~ 2.配置multipartResolver 1024 b=1kb 1024KB=1MB 1024MB=1GB 1024GB=1TB ~~~xml <!---CommonsMultipartResolver --> <!--切记:Spring是按照ID名称来进行装配的 CommonsMultipartResolver--> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <property name="defaultEncoding" value="UTF-8"></property> <property name="maxUploadSize" value="1024"></property> <!--MB--> </bean> ~~~ 3、修改表单信息 ~~~html <form action="/upload" method="post" enctype="multipart/form-data"> <input type="file" name="file" value="上传"><br/> <input type="submit" value="提交"/> </form> ~~~ 4、Controller代码 ~~~java package cn.hxzy.ticket.controller; import org.apache.commons.io.FilenameUtils; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.multipart.MultipartFile; import javax.servlet.http.HttpServletRequest; import java.io.File; import java.io.IOException; import java.util.UUID; @Controller public class UploadController { @RequestMapping(value = "/upload",method = RequestMethod.POST) public String upload(@RequestParam MultipartFile file, HttpServletRequest request){ //指定上传的路径 String path = request.getServletContext().getRealPath("/upload"); System.out.println(path); //上传文件的名称 String fileName = file.getOriginalFilename(); //得到扩展名 String exten = FilenameUtils.getExtension(fileName); //创建一个新的名称 String newFileName = UUID.randomUUID().toString().replaceAll("-", "")+"."+exten; File f=new File(path); if(!f.exists()){ f.mkdir();//创建upload文件夹 } try { file.transferTo(new File(f+"/"+newFileName)); return "index"; //纯服务器端的技术的话,返回逻辑视图名。 } catch (IOException e) { return "upload"; } } } ~~~ #### 7.5 ajax上传 前台页面 ~~~html <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>ajax上传</title> </head> <body> <form id="uploadForm" enctype="multipart/form-data"> 文件:<input id="file" type="file" name="file"/> </form> <button id="btn">上传文件</button> </body> <script src="/statics/js/jquery-3.6.0.js" type="text/javascript"></script> <script type="text/javascript"> $("#btn").click(function () { var formData = new FormData($('#uploadForm')[0]); $.ajax({ type: 'post', url: "/file/upload", //上传文件的请求路径必须是绝对路劲 data: formData, cache: false, //缓存关闭 processData: false, //ajax上传的对象,都会自动变为字符串。 contentType: false, success: function (data) { alert(data) alert("上传成功!") }, error: function (e) { alert("上传失败!"); } }) }); </script> </html> ~~~ 后台controller ~~~java package cn.hxzy.usermanager.controller; import org.apache.commons.io.FilenameUtils; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.multipart.MultipartFile; import javax.servlet.http.HttpServletRequest; import java.io.File; import java.io.IOException; import java.util.UUID; @Controller @RequestMapping("file") public class UploadController { @ResponseBody @RequestMapping("upload") public String upload(@RequestParam MultipartFile file, HttpServletRequest request){ //指定上传的路径 // String path = request.getServletContext().getRealPath("/upload"); String path = "D:/apache-tomcat-8.5.31/webapps/upload"; //上传文件的名称 String fileName = file.getOriginalFilename(); //得到扩展名 String exten = FilenameUtils.getExtension(fileName); //创建一个新的名称 String newFileName = UUID.randomUUID().toString().replaceAll("-", "")+"."+exten; File f=new File(path); if(!f.exists()){ f.mkdir();//创建upload文件夹 } try { file.transferTo(new File(f+"/"+newFileName)); return "success"; //纯服务器端的技术的话,返回逻辑视图名。 } catch (IOException e) { return "fail"; } } } ~~~ 8.6 layui的上传,一机部署多个tomcat.
11-15
263
![](https://csdnimg.cn/release/blogv2/dist/pc/img/readCountWhite.png)
03-15
1705
![](https://csdnimg.cn/release/blogv2/dist/pc/img/readCountWhite.png)