- 1》、什么是MVC?
- 2》、 使用SpringMvc:
- 2.1》HandlerMapping与处理映射器:
- 3》静态资源:
- 4》中文乱码问题:
- 5》请求方法参数名和字段名不一致怎么办?
- 6》Restful风格获取请求数据:
- 7》自定义类型转换器:
- 8》SpringMvc拦截器:
- 9》数据的加密与解密(AES):
- 10》 获取Servlet相关API:
- 11》获取请求头:
- 12》文件上传:
- 13》SpringMvc拦截器:
- 14》配置Tomcat虚拟路径:
15》SpringMvc异常处理:
1》、什么是MVC?
含义:SprinMVC 是一种基于java实现的MVC设计模型的请求驱动类型的轻量级的WEB层框架,属于Springframework的后续产品,已经融合在Springweb flow中。
Spring MVC已经成为目前主流的MVC框架之一,并随着任凭 3.0的发布,已经全面超越身体乳提升
struts2,成为最优秀的MVC框架,他通过一套注解,让一个简单的java类成为处理请求的控制器,而无需实现任何接口,同事还支持RESTful编程风格的请求。
1.MVC是模型(Model)、视图(View)、控制器(Controller)的简写,是一种软件设计规范。
2.是将业务逻辑、数据、显示分离的方法来组织代码。
3.MVC主要作用是降低了视图与业务逻辑间的双向偶合。
4.MVC不是一种设计模式,MVC是一种架构模式。当然不同的MVC存在差异。
Model(模型):数据模型,提供要展示的数据,因此包含数据和行为,可以认为是领域模型或JavaBean组件(包含数据和行为),不过现在一般都分离开来:Value Object(数据Dao) 和 服务层(行为Service)。也就是模型提供了模型数据查询和模型数据的状态更新等功能,包括数据和业务。
View(视图):负责进行模型的展示,一般就是我们见到的用户界面,客户想看到的东西。
Controller(控制器):接收用户请求,委托给模型进行处理(状态改变),处理完毕后把返回的模型数据返回给视图,由视图负责展示。也就是说控制器做了个调度员的工作。
最典型的MVC就是JSP + servlet + javabean的模式。
2》、 使用SpringMvc:
2.1》HandlerMapping与处理映射器:
1)SpringMvc的两大核心组件是ViewResolcer(用来处理逻辑视图名解析成实际的视图对象)和HandlerMapping(负责将请求映射到控制器的处理方法,就是当DispatcherServlet拦截到HTTP请求后,HandlerMapping负责告诉DispatcherServlet调用哪一个控制器那个方法来处理请求)。
2)目前HandlerMapping流行的实现类是RequestMappingHandlerMapping,他可以将HTTP请求映射到控制类中@RequestMapping修饰的方法。
2.1 导入依赖:
<!--springMvc依赖--><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>5.2.18.RELEASE</version></dependency>
2.2 配置控制器(web.xml配置文件中):
<!-- 加载Spring.xml配置文件--><context-param><param-name>contextConfigLocation </param-name><param-value>classpath:applicationContext.xml </param-value></context-param><!--监听器--><listener><listener-class>org.springframework.web.context.ContextLoaderListener </listener-class></listener><!--配置SpringMvc的前端控制器--><servlet><servlet-name>DispatcherServlet</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><!--在启动的时候呢加载springmvc配置文件--><init-param><param-name>contextConfigLocation</param-name><param-value>classpath:spring-mvc.xml</param-value></init-param><load-on-startup>1</load-on-startup></servlet><servlet-mapping><servlet-name>DispatcherServlet</servlet-name><url-pattern>/</url-pattern></servlet-mapping>
2.3 编写controller类:
package com.xxgc.spring.controller;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;//把web类交个spring托管@Controllerpublic class LoginController {//请求接口地址@RequestMapping("/login")public String userLogin(){return "";}}
2.4 配置spring-mvc.xml配置文件:

<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd"><!--配置Spring的controller主键扫描--><context:component-scan base-package="com.xxgc.spring.controller"/><!--开启注解扫描--><mvc:annotation-driven /><!--如果是静态之源就交给web应用服务器处理,否则DispatcherServlet处理--><mvc:default-servlet-handler/><!--配置视图解析器(前缀和后缀)--><bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"><!--视图解析器的前缀--><property name="prefix" value="/WEB-INF/jsp/"/><!--视图解析器的后缀--><property name="suffix" value=".jsp"/></bean><!--开放静态资源访问--><mvc:resources mapping="/js/**" location="/js/"/></beans>
2.5 返回数据+页面的使用:
在spring-mvc.xml配置视图解析器:
<!--配置视图解析器(前缀和后缀)--><bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"><!--视图解析器的前缀--><property name="prefix" value="/WEB-INF/jsp/"/><!--视图解析器的后缀--><property name="suffix" value=".jsp"/></bean>
@RequestMapping注解的使用:
/*** value="/login":代表请求路径* method = RequestMethod.POST :代表必须是POST请求* params = {"username","password"}:请求参数必须含有它俩* @param request* @return*/@RequestMapping(value = "/login3",method = RequestMethod.POST,params = {"username","password"})public String userLogin3(HttpServletRequest request){System.out.println("login3...");HttpSession session = request.getSession();session.setAttribute("msg","噢噢噢噢哦哦哦");return "login";}
@ResponseBody的使用:
ps:如果返回JSON格式的数据,则要导入以下依赖:
<!--springmvc返回json数据格式 数据绑定--><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.12.3</version></dependency>-
/*** 获取数据* @return*/@RequestMapping(value = "/login4")@ResponseBodypublic String userLogin4(@RequestParam("username")String username){System.out.println("login4...获取数据");return "{'username':'zhangsan','pass':'123456'}";}
ps:用了这个注解会跳过视图解析器,直接返回数据给页面
<!--开启注解扫描--><mvc:annotation-driven />
1、在SpringMvc的各个组件中,处理器、映射器、处理适配器 称为SpringMvc的三大组件。
2、使用了以上代码可以自动加载 RequestMappingHandlerMapping(处理映射器),和RequestMappingHandlerAdapler(处理适配器),来代替注解处理器和适配器的配置。
3、使用它,默认底层会集成jackson进行对象集合的JSON字符串转换。
2.6 获取请求数据参数:
服务器需要获取的参数有,有事还需要进行数据封装,SpringMvc可以接收如下类型参数:
2.6.1 基本类型参数:
Controller中业务方法的参数名称要求与请求参数name一致,参数会自动匹配。
@Controller@RequestMapping("/live")public class LiveController {@RequestMapping("/live1")@ResponseBodypublic void live1(Integer liveId,String liveName){System.out.println("进来了");System.out.println("直播间id = " + liveId);System.out.println("直播间name = " + liveName);}}
http://localhost:8080/springMvc/live1?liveId=1&liveName=LOL
ps:写了参数不一定不需要传递,可以传某个值,也可以完全不传。但要注意,不传值会给一个null,如果是int类型会报错,应该改为Integer。
2.6.2 POJO类型参数:
Controller中的业务方法的POJO的属性名一致,参数会自动映射匹配。
POJO:
package com.xxgc.spring.pojo;import lombok.AllArgsConstructor;import lombok.Data;import lombok.NoArgsConstructor;import org.springframework.stereotype.Component;@Data@AllArgsConstructor@NoArgsConstructor@Componentpublic class User {private long uId;private String userName;private String password;}
controller:
@Controller@RequestMapping("/live")public class LiveController {@RequestMapping("/live2")@ResponseBodypublic User live2(User user){System.out.println("进来了");System.out.println("user = " + user);return user;}}
http://localhost:8080/springMvc/live/live2?uId=1&userName=lisi
ps:在对象中,不需要传递所有参数,也可以不传,不传递会使用默认值null或0。
2.6.3 数组类行参数:
Controller中业务方法数组名称与请求参数name一致,参数会自动映射匹配。
@Controller@RequestMapping("/live")public class LiveController {@RequestMapping("/live3")@ResponseBodypublic String[] live3(String[] names){System.out.println(Arrays.asList(names));return names;}}
http://localhost:8080/springMvc/live/live3?names=zhangsan&names=lisi
ps:传递参数时,必须保证key的名称和方法参数名一致,否则拿不到。属性类型必须一致。
2.6.4 集合类型参数:
获取集合数据时,要将集合参数包装到一个POJO中才可以:
创建一个POJO:
@Datapublic class UserList {private List<User> users;}
编写页面:
<%@ page contentType="text/html;charset=UTF-8" language="java" %><html><head><title>Title</title></head><body><form action="${pageContext.request.contextPath}/live/live4" method="post"><input type="text" name="users[0].uId"/><input type="text" name="users[0].userName"/><input type="text" name="users[0].password"/><input type="text" name="users[1].uId"/><input type="text" name="users[1].userName"/><input type="text" name="users[1].password"/><button type="submit">登录</button></form></body></html>
编写Controller类:
@Controller@RequestMapping("/live")public class LiveController {@RequestMapping("/live4")@ResponseBodypublic void live4(UserList userList){System.out.println("live4进来了。。。。。");for (User user : userList.getUsers()) {System.out.println("user = " + user);}}}
2.6.5 集合参数二:
当使用ajax提交时,可以指定contentType为json格式,那么在方法参数使用位置使用@RequestBody可以直接接受集合数据而无需使用POJO进行包装。
Controller类:
@Controller@RequestMapping("/live")public class LiveController {@RequestMapping("/live5")@ResponseBodypublic void live5(@RequestBody List<User> users){for (User user : users) {System.out.println("user = " + user);}}}
apipost工具body属性中参数:
[{"userId": "1","userName": "zhangsan","password": "123456",},{"userId": "2","userName": "lisi","password": "555"}]

ps:调试工具
把body调成application/json
ajax:
Context-Type=json
3》静态资源:
3.1 方式一 、如果使用静态资源,则会被SpringMvc拦截,(需要在Spring-mvc.xml中配置以下信息:)
<!--开放静态资源访问--><mvc:resources mapping="/js/**" location="/js/"/><mvc:resources mapping="/images/**" location="/images/"/>
访问路径案例:http://localhost:8080/springMvc/js/jquery/jquery.js
3.2 方式二、 (配置全部静态资源):
<!--如果是静态之源就交给web应用服务器处理,否则DispatcherServlet处理--><mvc:default-servlet-handler/>
注意:加上之后,所有的静态资源都会被用户看到,如果不想被用户看到,就放到WEB_INF文件夹下面。
注意:
1.通常情况下我们把不容易发生改变的静态资源放在web文件夹下面的CDN文件夹下。
2.需要保密的静态资源放在WEB-IN下通过@RequestMapping获取。
4》中文乱码问题:
方案一:
在web.xml中配置:
<!--配置SpringMvc全局过滤器 解决乱码问题--><filter><filter-name>CharacterEncodingFilter</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><init-param><param-name>forceEncoding</param-name><param-value>true</param-value></init-param></filter><filter-mapping><filter-name>CharacterEncodingFilter</filter-name><url-pattern>/*</url-pattern></filter-mapping>
方案二:
spring-mvc中配置:
<mvc:annotation-driven><mvc:message-converters register-defaults="true"><bean class="org.springframework.http.converter.StringHttpMessageConverter"><property name="defaultCharset" value="UTF-8"/><property name="writeAcceptCharset" value="false"/></bean></mvc:message-converters></mvc:annotation-driven>
5》请求方法参数名和字段名不一致怎么办?
@RequestParam注解的使用:
使用场景:当某些字段需要隐藏其真实含义需要使用注解@RequestParam
@RequestParam(value = “liveId”,required = true,defaultValue = “1”):
value = “liveId”:代表参数名
@Controller@RequestMapping("/live")public class LiveController {@RequestMapping("/live1")@ResponseBodypublic void live1(@RequestParam(value = "liveId",required = true,defaultValue = "1") Integer liveId, @RequestParam("liveName") String liveName){System.out.println("进来了");System.out.println("直播间id = " + liveId);System.out.println("直播间name = " + liveName);}}
6》Restful风格获取请求数据:
restful+普通参数的使用:
@Controllerpublic class VideoController {@RequestMapping("/video/{videoUrl}")public String playViedo(@PathVariable("videoUrl")String videoUrl,@RequestParam("money")String money){System.out.println("videoUrl = " + videoUrl);System.out.println("money = " + money);return "";}}
http://localhost:8080/springMvc/video/HGHDL?money=1245
7》自定义类型转换器:
含义:
SpringMvc默认提供了一些常用的类型转换器,例如客户端提供的字符串转换为int、long进行参数设置。但是不是又有类型都提供了转换器,没有提供的就要自定义转换器,如:时间Data类型。
实现步骤:
1.定义一个转换器实现Converter接口
package com.xxgc.spring.converter;import org.springframework.core.convert.converter.Converter;import java.util.Date;public class DateConverter implements Converter<String,Date> {@Overridepublic Date convert(String s) {if(s==null){throw new RuntimeException("时间为空");}long longs = Long.parseLong(s);Date date = new Date();date.setTime(longs);System.out.println("date.getTime() = " + date.getTime());return date;}}
2.在配置文件中声明转换器
<!--声明转换器--><bean id="DateConverter" class="org.springframework.context.support.ConversionServiceFactoryBean"><property name="converters"><set><bean class="com.xxgc.spring.converter.DateConverter"></bean></set></property></bean>
3.在中引用
<mvc:annotation-driven conversion-service="DateConverter"></mvc:annotation-driven>
4.Controller类中的方法:
注意:定义类型转换器contorller方法参数必须是Date类型。
@Controllerpublic class VideoController {@RequestMapping("/vide/getVideoUrl")@ResponseBodypublic String routeTime(Date time){System.out.println("time = " + time);return "时间差="+time;}}
8》SpringMvc拦截器:
8.1 自定义拦截器类实现接口HandlerInterceptor:
preHandle——在向模型注入数据之前的操作
postHandle——模型被注入数据之后,返回视图之前的操作
afterCompletion——返回视图之后的操作
public class loginIntercepter implements HandlerInterceptor {public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {// 判断用户是否登录即判断session中有没有user对象HttpSession session = request.getSession();Object user = session.getAttribute("user");if (user==null){response.sendRedirect(request.getContextPath()+"/login.jsp");return false;}return true;}}
8.2 在spring-mvc.xml配置文件中注册拦截器:
<!-- 配置登录拦截器--><mvc:interceptors><mvc:interceptor><!-- 拦截哪些--><mvc:mapping path="/**"/><!-- 哪些不拦截--><mvc:exclude-mapping path="/css/**"/><mvc:exclude-mapping path="/plugins/**"/><mvc:exclude-mapping path="/img/**"/><!--配置哪些资源排除拦截操作--><mvc:exclude-mapping path="/user/login"/><!-- 自定义拦截器位置--><bean class="com.wzy.intercepter.loginIntercepter"/></mvc:interceptor></mvc:interceptors>
ps:返回值为true表示方行 false不放行进行拦截。
9》数据的加密与解密(AES):
9.1 在html静态文件中引入对应的js:
<script src="/springMvc/CDN/js/jquery/jquery.js"></script><%--加密使用的包--%><script src="https://cdn.bootcss.com/crypto-js/3.1.9-1/crypto-js.min.js"></script><script src="https://cdn.bootcdn.net/ajax/libs/aes-js/3.1.2/index.min.js"></script>
9.2 书写加减密的js:
// AES 加密,AES-128, AES-192, AES-256// AES-128: key和iv都是16个字节,16*8=128bit// AES-192: key和iv都是24个字节,24*8=128bit// AES-256: key和iv都是32个字节,32*8=128bit// iv 似乎一般都是纯数字// 例如:AES_encrypt_CBC('需要加密的内容', '1234567890123456', '1234567890654321');function AES_CBC_encrypt(message, key, iv) {// utf8字符串—>WordArray对象,WordArray是一个保存32位整数的数组,相当于转成了二进制let keyHex = CryptoJS.enc.Utf8.parse(key); //let ivHex = CryptoJS.enc.Utf8.parse(iv);let messageHex = CryptoJS.enc.Utf8.parse(message);let encrypted = CryptoJS.AES.encrypt(messageHex, keyHex, {iv: ivHex,mode: CryptoJS.mode.CBC,padding: CryptoJS.pad.Pkcs7});return encrypted.toString();// base64结果//return encrypted.ciphertext.toString(); // 二进制结果}// AES CBC模式解密function AES_CBC_decrypt(messageBase64, key, iv) {// 如果加密后没有转成base64,那么先要转成base64再传入//let encryptedHexStr = CryptoJS.enc.Hex.parse(word); // 从二进制文本转成二进制//messageBase64 = CryptoJS.enc.Base64.stringify(encryptedHexStr); // 转成base64let keyHex = CryptoJS.enc.Utf8.parse(key);let ivHex = CryptoJS.enc.Utf8.parse(iv);let decrypt = CryptoJS.AES.decrypt(messageBase64, keyHex, {iv: ivHex,mode: CryptoJS.mode.CBC,padding: CryptoJS.pad.Pkcs7});let decryptedStr = decrypt.toString(CryptoJS.enc.Utf8);return decryptedStr.toString();}// AES ECB模式加密,没有ivfunction AES_ECB_encrypt(message, key) {// utf8字符串—>WordArray对象,WordArray是一个保存32位整数的数组,相当于转成了二进制let keyHex = CryptoJS.enc.Utf8.parse(key); //let messageHex = CryptoJS.enc.Utf8.parse(message);let encrypted = CryptoJS.AES.encrypt(messageHex, keyHex, {mode: CryptoJS.mode.ECB,padding: CryptoJS.pad.Pkcs7});return encrypted.toString();// base64结果//return encrypted.ciphertext.toString(); // 二进制结果}// AES ECB模式解密function AES_ECB_decrypt(messageBase64, key) {// 如果加密后没有转成base64,那么先要转成base64再传入//let encryptedHexStr = CryptoJS.enc.Hex.parse(word); // 从二进制文本转成二进制//messageBase64 = CryptoJS.enc.Base64.stringify(encryptedHexStr); // 转成base64let keyHex = CryptoJS.enc.Utf8.parse(key);let decrypt = CryptoJS.AES.decrypt(messageBase64, keyHex, {mode: CryptoJS.mode.ECB,padding: CryptoJS.pad.Pkcs7});let decryptedStr = decrypt.toString(CryptoJS.enc.Utf8);return decryptedStr.toString();}
9.3 使用案例:
<body><form action="/userRegister" method="post" onsubmit="">昵称:<input type="text" placeholder="请输入昵称" name="nick"/>密码:<input type="password" name="pass"/>手机号码:<input type="text" placeholder="请输入手机号码" name="phone"/>验证码: <input type="text" name="smsvc"/><input id="submit" type="button" value="提交"></form><script>let key = "${key}";// AES ECB模式加密,没有ivfunction AES_ECB_encrypt(message, key) {// utf8字符串—>WordArray对象,WordArray是一个保存32位整数的数组,相当于转成了二进制let keyHex = CryptoJS.enc.Utf8.parse(key); //let messageHex = CryptoJS.enc.Utf8.parse(message);let encrypted = CryptoJS.AES.encrypt(messageHex, keyHex, {mode: CryptoJS.mode.ECB,padding: CryptoJS.pad.Pkcs7});return encrypted.toString();// base64结果//return encrypted.ciphertext.toString(); // 二进制结果}/*ES6代码规范*/$(function(){$("#submit").on("click",function(){let nick = $("input[name='nick']").val();//对数据进行加密let pass = AES_ECB_encrypt($("input[name='pass']").val(),key);let phone = AES_ECB_encrypt($("input[name='phone']").val(),key);let smsvc = $("input[name='smsvc']").val();$.ajax({type:"post",url:"/springMvc/userRegister",contextType:"application/json",dataType:"json",data:{nick:nick,pass:pass,phone:phone,smsvc:smsvc},success:function(data){//成功回调console.log(data)},error:function(){//失败是回调}});})})</script></body>
9.4 java后台的加减密工具类:
/*** @author ybakiame* @className AESCrypt* @description AES加解密工具,AES-128: key和iv都是16个字节,16*8=128bit,java似乎只支持AES-128* @createTime 2021/11/15 21:19*/public class AESCrypt {/*** AES CBC 加密* @param message 需要加密的字符串* @param key 密匙* @param iv IV,需要和key长度相同* @return 返回加密后密文,编码为base64*/public static String encryptCBC(String message, String key, String iv) {final String cipherMode = "AES/CBC/PKCS5Padding";final String charsetName = "UTF-8";try {byte[] content = new byte[0];content = message.getBytes(charsetName);//byte[] keyByte = key.getBytes(charsetName);SecretKeySpec keySpec = new SecretKeySpec(keyByte, "AES");//byte[] ivByte = iv.getBytes(charsetName);IvParameterSpec ivSpec = new IvParameterSpec(ivByte);Cipher cipher = Cipher.getInstance(cipherMode);cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);byte[] data = cipher.doFinal(content);final Base64.Encoder encoder = Base64.getEncoder();final String result = encoder.encodeToString(data);return result;} catch (UnsupportedEncodingException | NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | InvalidAlgorithmParameterException | IllegalBlockSizeException | BadPaddingException e) {e.printStackTrace();}return null;}/*** AES CBC 解密* @param messageBase64 密文,base64编码* @param key 密匙,和加密时相同* @param iv IV,需要和key长度相同* @return 解密后数据*/public static String decryptCBC(String messageBase64, String key, String iv) {final String cipherMode = "AES/CBC/PKCS5Padding";final String charsetName = "UTF-8";try {final Base64.Decoder decoder = Base64.getDecoder();byte[] messageByte = decoder.decode(messageBase64);//byte[] keyByte = key.getBytes(charsetName);SecretKeySpec keySpec = new SecretKeySpec(keyByte, "AES");//byte[] ivByte = iv.getBytes(charsetName);IvParameterSpec ivSpec = new IvParameterSpec(ivByte);Cipher cipher = Cipher.getInstance(cipherMode);cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);byte[] content = cipher.doFinal(messageByte);String result = new String(content, charsetName);return result;} catch (Exception e) {e.printStackTrace();}return null;}/*** AES ECB 加密* @param message 需要加密的字符串* @param key 密匙* @return 返回加密后密文,编码为base64*/public static String encryptECB(String message, String key) {final String cipherMode = "AES/ECB/PKCS5Padding";final String charsetName = "UTF-8";try {byte[] content = new byte[0];content = message.getBytes(charsetName);//byte[] keyByte = key.getBytes(charsetName);SecretKeySpec keySpec = new SecretKeySpec(keyByte, "AES");Cipher cipher = Cipher.getInstance(cipherMode);cipher.init(Cipher.ENCRYPT_MODE, keySpec);byte[] data = cipher.doFinal(content);final Base64.Encoder encoder = Base64.getEncoder();final String result = encoder.encodeToString(data);return result;} catch (UnsupportedEncodingException | NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException e) {e.printStackTrace();}return null;}/*** AES ECB 解密* @param messageBase64 密文,base64编码* @param key 密匙,和加密时相同* @return 解密后数据*/public static String decryptECB(String messageBase64, String key) {final String cipherMode = "AES/ECB/PKCS5Padding";final String charsetName = "UTF-8";try {final Base64.Decoder decoder = Base64.getDecoder();byte[] messageByte = decoder.decode(messageBase64);//byte[] keyByte = key.getBytes(charsetName);SecretKeySpec keySpec = new SecretKeySpec(keyByte, "AES");Cipher cipher = Cipher.getInstance(cipherMode);cipher.init(Cipher.DECRYPT_MODE, keySpec);byte[] content = cipher.doFinal(messageByte);String result = new String(content, charsetName);return result;} catch (Exception e) {e.printStackTrace();}return null;}public static void main(String[] args) {String content = "测试8";String encrypt = AESCrypt.encryptECB(content,"abcdefgabcdefg12");String decrypt = AESCrypt.decryptECB(encrypt, "abcdefgabcdefg12");System.out.println(content);System.out.println(encrypt);System.out.println(decrypt);}}
9.5 后台的使用案例:
/*** 注册方法* @return Info* "version v1.0* @Date 2021-11-16**/@RequestMapping("/userRegister")@ResponseBodypublic Info userRegister(UserRegisterInfo userRegisterInfo) throws Exception {userRegisterInfo.setPhone(DESUtil.decryptECB(userRegisterInfo.getPhone(),DESUtil.KEY));userRegisterInfo.setPass(DESUtil.decryptECB(userRegisterInfo.getPass(),DESUtil.KEY));return new Info(200,"注册成功","注册成功",userRegisterInfo);}
10》 获取Servlet相关API:
SpringMvc支持使用原始的ServletAPI对象作为控制器方法的参数进行注入,
10.1 HttpServletRequest:
10.2 HttpServletResponse:
10.3 HttpSession:
/*** 获取原生ServletAPI**/@RequestMapping("/userLogin8")@ResponseBodypublic void userLogin8(HttpServletRequest request, HttpServletResponse response,HttpSession session){System.out.println("request = " + request);System.out.println("response = " + response);System.out.println("session = " + session);}
11》获取请求头:
11.1 @RequestHeader注解:
使用@RequestHeader可以获取请求信息,相当于web阶段血虚的request.getHeader(name)
11.1 @RequestHeader注解的属性如下:
1 value:请求头的名称:
2 required:是否必须携带请求头:
/***@RequestHeader(value="referer",required = true)* value:请求头名* required:是否必须带参数* @return*/@RequestMapping("/userLogin9")@ResponseBodypublic String userLogin9(@RequestHeader(value="referer",required = true)String headerReferer,@RequestHeader(value="key",required = true)String key){if(headerReferer.equals("www.bilibili.com")){return "请求成功";}else{return "失败";}}
11.2 @CookieValue注解:
@CookieValue的属性如下:
1 value:指定cookie的名称
2 required:是否必须携带Cookie信息
@RequestMapping("/userLogin10")@ResponseBodypublic String userLogin10(@CookieValue(value = "JSESSIONID",required = true)String jessionid,@CookieValue(value = "Idea-a1ffd5d4")String Idea){return jessionid+"--"+Idea;}

哔哩哔哩cookie用SESSDATA保存登录信息。
12》文件上传:
12.1 文件上传的三大条件:
<a name="wLiEl"></a>### 12.2.2 导包:```xml<!--文件上传--><dependency><groupId>commons-fileupload</groupId><artifactId>commons-fileupload</artifactId><version>1.4</version></dependency><dependency><groupId>commons-io</groupId><artifactId>commons-io</artifactId><version>2.6</version></dependency>
12.2.3 speing-mvc.xml配置文件上传解析器信息:
<!--配置MUltipartResolver,用于文件上传--><bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"><!--上传文件大小上限--><property name="maxInMemorySize" value="5242800"/><!--请求编码格式--><property name="defaultEncoding" value="UTF-8"/><!--上传单个文件大小--><property name="maxUploadSizePerFile" value="5242800"/></bean>
12.2.4 编写controller:
@RequestMapping("/fileUpdate1")public void fileUpdate1(String nick,MultipartFile file) throws IOException {//方案一 日期文件夹SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");String format = simpleDateFormat.format(new Date());//方案二:UUIDString s = UUID.randomUUID().toString().replaceAll("-", "");String filenameExtension = StringUtils.getFilenameExtension(file.getOriginalFilename());//判断文件是否存在 不存在就创建一个File fileName = new File("D:\\upload\\"+format);if(!fileName.exists()){fileName.mkdirs();}String str = format+"/"+s+"."+filenameExtension;strings.add("/upload/"+str);//上传文件file.transferTo(new File("D:/upload",format+"/"+s+"."+filenameExtension));}
12.2.5 MultipartFile的内部方法:
12.2.5.1.判断上传的是不是图片:
//判断上传的是不是图片boolean image = file.getContentType().toLowerCase().startsWith("image");
12.2.5.2 获取文件上传大小:
//文件上传大小long size = file.getSize();
12.2.5.3 上传文件:
//上传文件file.transferTo(new File(""));
12.2.6 文件上传解决文件名冲突:
方案一:使用日期文件夹
方案二:使用UUID创建随机名
@RequestMapping("/fileUpdate1")public void fileUpdate1(String nick,MultipartFile file) throws IOException {//方案一 日期文件夹SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");String format = simpleDateFormat.format(new Date());//方案二:UUIDString s = UUID.randomUUID().toString().replaceAll("-", "");String filenameExtension = StringUtils.getFilenameExtension(file.getOriginalFilename());//判断文件是否存在 不存在就创建一个File fileName = new File("D:\\upload\\"+format);if(!fileName.exists()){fileName.mkdirs();}String str = format+"/"+s+"."+filenameExtension;strings.add("/upload/"+str);//上传文件file.transferTo(new File("D:/upload",format+"/"+s+"."+filenameExtension));}
12.2.7 多文件上传:
<%@ page contentType="text/html;charset=UTF-8" language="java" %><html><head><title>多文件上传</title></head><body><form action="${pageContext.request.contextPath}/file/uploadFiles" method="post" enctype="multipart/form-data">文件1:<input type="file" name="uploadImgs"><br>文件2:<input type="file" name="uploadImgs"><br>文件3:<input type="file" name="uploadImgs"><br><button type="submit">提交</button></form></body></html>
@RequestMapping("/uploadFiles")@ResponseBodypublic List uploadFiles(MultipartFile[] uploadImgs) throws IOException {List<String> strings = new ArrayList<String>();for (MultipartFile uploadImg : uploadImgs) {//方案1 日期文件夹String yyyyMMdd = new SimpleDateFormat("yyyyMMdd").format(new Date());//方案2 UUIDString uuid = UUID.randomUUID().toString().replace("-", "");//截取后缀String suffix = StringUtils.getFilenameExtension(uploadImg.getOriginalFilename());//文件名String fileName = yyyyMMdd+"\\"+uuid+"."+suffix;uploadImg.transferTo(new File("D:\\upload\\"+fileName));strings.add("\\abb\\"+fileName);}return strings;}
13》SpringMvc拦截器:
13.1 含义:
SpringMvc的拦截器类似于Servlet的过滤器Filter,用于对请求处理器进行预处理和后处理。
将拦截按一定的顺序结成一条链,这条链称为拦截器链(Interceptor Chain),在访问被拦截的方法或字段时,拦截器链中的拦截器就会按其之前定义的顺序被调用。拦截器也是Aop思想的具体体现。
13.2 拦截器和过滤去的区别:
| 区别 | 过滤器 | 拦截器 |
|---|---|---|
| 使用范围 | 是servlet规范中的一部分,任何JavaWeb下都可以使用 | 是SpringMvc框架自己的,只有使用了SpringMvc框架的工程才可以使用 |
| 拦截范围 | 在url-pattern中配置/*过后,可以对所有要访问的资源拦截 | 在 |
13.3 拦截器的实现:
13.3.1 自定义类实现HandlerInterceptor接口:
package com.xxgc.spring.interceptor;import org.springframework.web.servlet.HandlerInterceptor;import org.springframework.web.servlet.ModelAndView;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;/*** @program: spring-study* @Email:2119196781@qq.com* @description* @author: 小唐唐* @create: 2021-11-18 10:41**/public class MyInterceptor implements HandlerInterceptor {//在目标方法之前执行@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {System.out.println("目标之前");return false;}//在目标方法之后执行,视图对象返回之前执行@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {System.out.println("目标之后");}//在所有流程执行完之后执行@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {System.out.println("所有都执行后 执行完了");}}
1.3.2 在Spring-mvc.xml配置文件中配置拦截器:
<!--配置拦截器--><mvc:interceptors><mvc:interceptor><!--对那些操作进行拦截--><mvc:mapping path="/**"/><bean class="com.xxgc.spring.interceptor.MyInterceptor"/></mvc:interceptor></mvc:interceptors>
14》配置Tomcat虚拟路径:
注意:单机使用虚拟路径,分布式环境使用OSS对象存储。
把请求url映射到本地的文件夹,一般用户文件上传之后的回显问题。
选择好文件夹过后,下面会有一个与文件夹对应的url地址
15》SpringMvc异常处理:
15.1 什么是异常?
在系统中异常包括两类:
预期异常和运行时异常RuntimeException,前者通过捕获异常从而获取异常信息,后者主要通过规范代码开发、测试等手段减少运行时异常的发生。
系统的dao,service,controller出现异常都通过throws Exception向上抛出,最后由SpringMvc前端控制器交由异常处理器进行异常处理。
15.2 SpringMvc异常处理的两种方式:
15.2.1 使用SpringMvc提供的简单的异常处理器SimpleMappingExceptionResolver
<!--简单异常处理器--><bean id="exceptionResolver" class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"><!--默认错误视图--><property name="defaultErrorView" value="error"/></bean>
15.2.1.2 自定义异常页面跳转:
<!--简单异常处理器--><bean id="exceptionResolver" class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"><!--默认错误视图--><!-- value="error" error代表错误的页面--><property name="defaultErrorView" value="error"/><property name="exceptionMappings"><map><!--自定义异常跳转--><entry key="java.io.FileNotFoundException" value="file_error"/></map></property></bean>
@RequestMapping("/live16")@ResponseBodypublic String test1() throws FileNotFoundException {System.out.println("进来了");FileInputStream file = new FileInputStream("f://testfff");return "";}
15.2.2 实现Spring的异常处理接口HandlerExcertionResolver自定义自己的异常处理器
15.2.2.1 创建异常处理实现HandlerExceptionResolver
package com.xxgc.spring.resolver;import org.springframework.web.servlet.HandlerExceptionResolver;import org.springframework.web.servlet.ModelAndView;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.FileNotFoundException;public class LoginExceptionResolver implements HandlerExceptionResolver {@Overridepublic ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {ModelAndView modelAndView = new ModelAndView();if(e instanceof FileNotFoundException){modelAndView.addObject("msg","文件异常");modelAndView.addObject("code","Foo_sdsa");modelAndView.setViewName("file_error");}else{modelAndView.setViewName("error");}return modelAndView;}}
15.2.2.2 配置异常处理器
<!-- 自定义异常处理器--><bean id="loginExceptionResolver" class="com.xxgc.spring.resolver.LoginExceptionResolver"/>
执行流程:
Spring MVC的特点:
- 轻量级,简单易学
- 高效 , 基于请求响应的MVC框架
- 与Spring兼容性好,无缝结合
- 约定优于配置
- 功能强大:RESTful、数据验证、格式化、本地化、主题等
- 简洁灵活
- Spring的web框架围绕DispatcherServlet [ 调度Servlet ] 设计。
DispatcherServlet的作用是将请求分发到不同的处理器。从Spring 2.5开始,使用Java 5或者以上版本的用户可以采用基于注解形式进行开发,十分简洁;
SpringMVC的原理:
当发起请求时被前置的控制器拦截到请求,根据请求参数生成代理请求,找到请求对应的实际控制器,控制器处理请求,创建数据模型,访问数据库,将模型响应给中心控制器,控制器使用模型与视图渲染视图结果,将结果返回给中心控制器,再将结果返回给请求者。
SpringMvc简要分析执行流程:
- DispatcherServlet表示前置控制器,是整个SpringMVC的控制中心。用户发出请求,DispatcherServlet接收请求并拦截请求。
- 我们假设请求的url为 : http://localhost:8080/SpringMVC/hello
- 如上url拆分成三部分:
- http://localhost:8080服务器域名
- SpringMVC部署在服务器上的web站点
- hello表示控制器
- 通过分析,如上url表示为:请求位于服务器localhost:8080上的SpringMVC站点的hello控制器。
- HandlerMapping为处理器映射。DispatcherServlet调用HandlerMapping,HandlerMapping根据请求url查找Handler。
- HandlerExecution表示具体的Handler,其主要作用是根据url查找控制器,如上url被查找控制器为:hello。
- HandlerExecution将解析后的信息传递给DispatcherServlet,如解析控制器映射等。
- HandlerAdapter表示处理器适配器,其按照特定的规则去执行Handler。
- Handler让具体的Controller执行。
- Controller将具体的执行信息返回给HandlerAdapter,如ModelAndView。
- HandlerAdapter将视图逻辑名或模型传递给DispatcherServlet。
- DispatcherServlet调用视图解析器(ViewResolver)来解析HandlerAdapter传递的逻辑视图名。
- 视图解析器将解析的逻辑视图名传给DispatcherServlet。
- DispatcherServlet根据视图解析器解析的视图结果,调用具体的视图。
-
SpringMvc配置:
1.导入依赖:
<dependency><groupId>org.springframework</groupId><artifactId>spring-web</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>${spring.version}</version></dependency>
2.配置web.xml , 注册DispatcherServlet: ```xml <?xml version=”1.0” encoding=”UTF-8”?>
3.编写SpringMVC 的 配置文件!名称:springmvc-servlet.xml : [servletname]-servlet.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"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd"></beans>
5、添加 处理映射器
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
6、添加 处理器适配器
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
7、添加 视图解析器
<!--视图解析器:DispatcherServlet给他的ModelAndView--><bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="InternalResourceViewResolver"><!--前缀--><property name="prefix" value="/WEB-INF/jsp/"/><!--后缀--><property name="suffix" value=".jsp"/></bean>
8、编写我们要操作业务Controller ,要么实现Controller接口,要么增加注解;需要返回一个ModelAndView,装数据,封视图;
package com.kuang.controller;import org.springframework.web.servlet.ModelAndView;import org.springframework.web.servlet.mvc.Controller;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;//注意:这里我们先导入Controller接口public class HelloController implements Controller {public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {//ModelAndView 模型和视图ModelAndView mv = new ModelAndView();//封装对象,放在ModelAndView中。Modelmv.addObject("msg","HelloSpringMVC!");//封装要跳转的视图,放在ModelAndView中mv.setViewName("hello"); //: /WEB-INF/jsp/hello.jspreturn mv;}}
9、将自己的类交给SpringIOC容器,注册bean
<!--Handler--><bean id="/hello" class="com.kuang.controller.HelloController"/>
10、写要跳转的jsp页面,显示ModelandView存放的数据,以及我们的正常页面;
<%@ page contentType="text/html;charset=UTF-8" language="java" %><html><head><title>Kuangshen</title></head><body>${msg}</body></html>
11、配置Tomcat 启动测试!
SpringMvc注解版本:
1.Maven可能存在资源过滤的问题
<build><resources><resource><directory>src/main/java</directory><includes><include>**/*.properties</include><include>**/*.xml</include></includes><filtering>false</filtering></resource><resource><directory>src/main/resources</directory><includes><include>**/*.properties</include><include>**/*.xml</include></includes><filtering>false</filtering></resource></resources></build>
ps:/ 和 /* 的区别:
1.< url-pattern > / </ url-pattern > 不会匹配到.jsp, 只针对我们编写的请求;即:.jsp 不会进入spring的 DispatcherServlet类 。
2.< url-pattern > / </ url-pattern > 会匹配 .jsp,会出现返回 jsp视图 时再次进入spring的DispatcherServlet 类,导致找不到对应的controller所以报404错。
2.SpringMvc配置:
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xmlns:mvc="http://www.springframework.org/schema/mvc"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttps://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/mvchttps://www.springframework.org/schema/mvc/spring-mvc.xsd"><!-- 自动扫描包,让指定包下的注解生效,由IOC容器统一管理 --><context:component-scan base-package="com.kuang.controller"/><!-- 让Spring MVC不处理静态资源 --><mvc:default-servlet-handler /><!--支持mvc注解驱动在spring中一般采用@RequestMapping注解来完成映射关系要想使@RequestMapping注解生效必须向上下文中注册DefaultAnnotationHandlerMapping和一个AnnotationMethodHandlerAdapter实例这两个实例分别在类级别和方法级别处理。而annotation-driven配置帮助我们自动完成上述两个实例的注入。--><mvc:annotation-driven /><!-- 视图解析器 --><bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"id="internalResourceViewResolver"><!-- 前缀 --><property name="prefix" value="/WEB-INF/jsp/" /><!-- 后缀 --><property name="suffix" value=".jsp" /></bean></beans>
3.创建controller:
package com.kuang.controller;import org.springframework.stereotype.Controller;import org.springframework.ui.Model;import org.springframework.web.bind.annotation.RequestMapping;@Controller@RequestMapping("/HelloController")public class HelloController {//真实访问地址 : 项目名/HelloController/hello@RequestMapping("/hello")public String sayHello(Model model){//向模型中添加属性msg与值,可以在JSP页面中取出并渲染model.addAttribute("msg","hello,SpringMVC");//web-inf/jsp/hello.jspreturn "hello";}}
4.解决中文乱码问题:
<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>


