文章目錄
- 1.springmvc介紹
- 2.簡單入門
- 2.1匯入jar
- 2.2.配置xml
- 2.3配置web.xml
- 2.4入門程式
- 3.入門案列決議
- 3.1流程(非常重要)
- 3.2注解
- 4.json引數回傳
- 4.1說明與基本配置
- 4.2map型別
- 4.3物件型別
- 4.4陣列型別
- 4.5集合型別
- 4.6基本資料型別+日期型別(看原始碼再說)
- 5.請求引數
- 中文請求亂碼
- 1.基本型別:注意使用包裝型別 避免出轉換例外
- 2.接收陣列 requestparam注解
- 3.物件接收
- 4.@requestBody:接收前臺的json物件
- 5.集合接收
- 6.日期轉換
- 6.總結
- 6.1后端傳遞到前臺
- 6.2前端傳遞到后端
- 6.3HTTP的常見code編號
- 6.4注解
- 7.檔案上傳
- 8.攔截器
- 9.引數校驗
- 10.統一例外攔截
- 11.swagger集成
配套視頻地址:https://search.bilibili.com/all?keyword=%E7%AB%B9%E6%9D%96%E9%9D%92%E8%A1%ABA&from_source=nav_search&spm_id_from=333.851.b_696e7465726e6174696f6e616c486561646572.11
Mvc:軟體設計架構,解除v層的耦合,希望只寫一套后臺代碼,就可以滿足各種v端
1.springmvc介紹
1.接受前臺或者其它服務的資料,并校驗 json
2.回傳資料給前端或者其它服務 json,流
3.指定跳轉的頁面或者其它服務 重定向或者跳轉
資料介面
2.簡單入門
2.1匯入jar
spring-context
spring-context-support
spring-web
spring-webmvc
servlet-api
jsp-api
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.11.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context-support -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>5.2.11.RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-web -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.2.11.RELEASE</version>
</dependency><!-- https://mvnrepository.com/artifact/org.springframework/spring-web -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.11.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.servlet/servlet-api -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.servlet.jsp/javax.servlet.jsp-api -->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.3.1</version>
<scope>provided</scope>
</dependency>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.6.0</version>
<configuration>
<source>1.8</source> <!-- 源代碼使用jdk1.8支持的特性 -->
<target>1.8</target> <!-- 使用jvm1.8編譯目標代碼 -->
<compilerArgs> <!-- 傳遞引數 -->
<arg>-parameters</arg>
<arg>-Xlint:unchecked</arg>
<arg>-Xlint:deprecation </arg>
</compilerArgs>
</configuration>
</plugin>
</plugins>
</build>
2.2.配置xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
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
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 配置spring創建容器時要掃描的包 cn.cdqf.web+類名就可以使用反射啦-->
<context:component-scan base-package="cn.cdqf.web"></context:component-scan>
<!-- 配置視圖決議器 -->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/"></property>
<property name="suffix" value=".html"></property>
</bean>
<!-- 配置spring開啟注解mvc的支持-->
<mvc:annotation-driven></mvc:annotation-driven>
</beans>
2.3配置web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<!-- SpringMVC的核心控制器 -->
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 配置Servlet的初始化引數,讀取springmvc的組態檔,創建spring容器 -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<!-- 配置servlet啟動時加載物件 -->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!--避免springmvc攔截以html結尾的請求-->
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.html</url-pattern>
</servlet-mapping>
</web-app>
2.4入門程式
package cn.cdqf.web;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
//標記這個類 要交給spring管理
@Controller//指定當前類要交給springmvc管理
@RequestMapping("test")//指定路徑
public class TestController {
//指定路徑的注解 RequestMapping+RequestMapping
@RequestMapping("test01")
public String test01(){
System.out.println("hello springmvc");
return "abc";
}
}
測驗:訪問http://localhost:xxxx/test/test01
使用modelAndview視圖:
package cn.cdqf.web;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
//標記這個類 要交給spring管理
@Controller//指定當前類要交給springmvc管理
@RequestMapping("test")//指定路徑
public class TestController {
//指定路徑的注解 RequestMapping+RequestMapping
@RequestMapping(value = "test01",method = RequestMethod.POST
,consumes="text/html")
public ModelAndView test01(){
//資料+試圖
ModelAndView modelAndView = new ModelAndView();
//request.setAttribute();
modelAndView.addObject("name","zhangsan");
modelAndView.setViewName("abc");
System.out.println("hello springmvc");
return modelAndView;
}
}
測驗:訪問http://localhost:xxxx/test/test01 會默認跳轉到http://localhost:xxxx/test/abc路徑
abc沒有寫前面的下劃線就是相對路徑,相對于當前controller而言,如果寫了**/abc**就是絕對路徑,訪問了就是http://localhost:xxx/abc了
3.入門案列決議
后面的springmvc原始碼學習還會詳細的學習這塊
3.1流程(非常重要)
初始化容器的時候,tomcat會讀取xml檔案------->dispatchServlet(初始化這個類)------>contextConfigLocation
------->springmvc.xml-------->base-package=“cn.cdqf.web”(掃描這個包)------>遞回讀取下面所有java檔案---->
cn.cdqf.web.TestController(反射class.forName(""))------>獲得class物件------>反射獲得注解(@Controller有這個標記的類就是要交給springmvc管理的類)------>類上面requestMapping(namespace)------->再讀取方法上面的
requestMapping兩個requestMapping組成該方法對應的唯一路徑
/test/test01----->public String test01()(Method物件) .invoke(某個物件,引數)
handlerMapping類 屬性:url Method Object(conrtroller物件)
List<HandlerMapping> handlerMappings; 描述了url與handler,method的對應關系
HandlerAdapter:呼叫方法,適配引數
List<HandlerAdapter> handlerAdapters;
ModelAndView:資料視圖
ViewResolver:視圖決議器
abc.html--->io流讀取到里面所有內容(字串)----${name}(正則運算式)---->去除${}---->name---->request.getAttribute("name");

url---->dispatchservlet----->handlerMapping(根據前端url,找對應handler(幾個重要屬性url,method,Object)以及Method)---->找不到就404,找到了就回傳method,object(controller物件,框架幫我們通過反射創建)---->
交給handleradpater(適配引數,呼叫方法method.invoke(物件,引數))------>modelAndview(資料與視圖)----->
viewResolver(視圖決議)------>前端
3.2注解
@Controller
@RequestMapping
RequestMapping是一個用來處理請求地址映射的注解,可用于類或方法上,用于類上,表示類中的所有回應請求的方法都是以該地址作為父路徑,
6種屬性:
value: 指定請求的實際地址,指定的地址可以是URI Template 模式;url
method: 指定請求的method型別, GET、POST、PUT、DELETE等;默認用get請求
consumes: 指定處理請求的提交內容型別(Content-Type),例如application/json, text/html;
produces: 指定回傳的內容型別,僅當request請求頭中的(Accept)型別中包含該指定型別才回傳;
params: 指定request中必須包含某些引數值是,才讓該方法處理,
headers: 指定request中必須包含某些指定的header值,才能讓該方法處理請求
從定向與跳轉
package cn.cdqf.web;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
//標記這個類 要交給spring管理
@Controller//指定當前類要交給springmvc管理
@RequestMapping("test")//指定路徑
public class TestController {
//指定路徑的注解 RequestMapping+RequestMapping
@RequestMapping(value = "test01",method = RequestMethod.POST
,consumes="text/html")
public ModelAndView test01(){
//資料+試圖
ModelAndView modelAndView = new ModelAndView();
//request.setAttribute();
modelAndView.addObject("name","zhangsan");
modelAndView.setViewName("abc");
System.out.println("hello springmvc");
return modelAndView;
}
//test/index
@RequestMapping("index")
public String index(){
//默認是跳轉
//return "abc";
return "abc";
}
@RequestMapping("indexA")
public String indexA(){
//默認是跳轉
//return "abc";
//重定向 上面的方法
return "redirect:/test/index";
}
@RequestMapping("indexC")
public String indexC(){
//默認是跳轉
//return "abc";
//重定向
return "redirect:https://www.baidu.com/";
}
}
4.json引數回傳
4.1說明與基本配置
注:jsp已經過時,前后端分離開發現在是主流,該課程只講解前后端分離的ajax請求,全部使用json傳遞資料
匯入json jar
Jackson fastJson GSON
<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.73</version>
</dependency>
<!-- 配置spring開啟注解mvc的支持-->
<mvc:annotation-driven></mvc:annotation-driven>
<mvc:annotation-driven>
<!--不使用默認訊息轉換器 -->
<mvc:message-converters register-defaults="false">
<!--spring訊息轉換器 -->
<bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter"/>
<bean class="org.springframework.http.converter.BufferedImageHttpMessageConverter"/>
<!--解決@Responcebody中文亂碼問題 -->
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<constructor-arg value="UTF-8"/>
</bean>
<!--配合fastjson支持 -->
<bean class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter">
<property name="defaultCharset" value="UTF-8"/>
<property name="supportedMediaTypes">
<list>
<!--順序保持這樣,避免IE下載出錯 配置1.注意編碼 2.注意與下載檔案沖突-->
<value>text/html;charset=UTF-8</value>
<value>application/json</value>
</list>
</property>
<property name="fastJsonConfig" ref="fastJsonConfig"/>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
<!--fastJsonConfig 這里面的配置需要開發中 跟前端進行協商-->
<bean id="fastJsonConfig" class="com.alibaba.fastjson.support.config.FastJsonConfig">
<!--默認編碼格式 -->
<property name="charset" value="UTF-8"/>
<property name="serializerFeatures">
<list>
<!--3.需要指定null按照協商好的配置回傳-->
<!-- List欄位如果為null,輸出為[]-->
<value>WriteNullListAsEmpty</value>
<!--4.日期格式
使得回傳的日期型別默認為yyyy-MM-dd hh:mm:ss
-->
<value>WriteDateUseDateFormat</value>
<!--美化格式-->
<value>PrettyFormat</value>
<value>WriteMapNullValue</value>
<value>WriteNullStringAsEmpty</value>
<!--禁止回圈參考檢測
Teacher : List<Student>
Student : Teacher
stackOverFlow:
@Transient
-->
<value>DisableCircularReferenceDetect</value>
</list>
</property>
匯入jquery,bootsrap靜態資源需要的包(見resouces目錄),配置放過js檔案
因為在springmvc中配置的路徑攔截是/表示攔截所有,那么請求靜態資源也會被攔截,所以得放過靜態資源,百度搜索:springmvc放過靜態資源
<!-- 對指定目錄下的靜態資源放行 -->
<mvc:resources location="/fonts/" mapping="/fonts/**"/>
<mvc:resources location="/css/" mapping="/css/**"/>
<mvc:resources location="/js/" mapping="/js/**"/>
前端代碼
<link href="/css/bootstrap.min.css">
<script src="/js/jquery-3.3.1.min.js"></script>
<script src="/js/bootstrap.min.js"></script>
</head>
<body>
<button id="ajax">點擊</button>
</body>
<script>
$(function () {
$("#ajax").click(function () {
$.ajax({
url:"/ajax/ajax1",
type:"GET",
dataType:"json",//回傳資料型別
success:function (data) {
console.log(data);
}
})
})
})
</script>
4.2map型別
4.3物件型別
4.4陣列型別
4.5集合型別
4.6基本資料型別+日期型別(看原始碼再說)
回傳json代碼:

package cn.cdqf.web;
import cn.cdqf.pojo.Student;
import cn.cdqf.pojo.Teacher;
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.ResponseBody;
import java.util.*;
@Controller
@RequestMapping("/json")
public class JsonController {
/**
* 經過配置 已經告訴了springmvc如果用戶需要把回傳值轉換成json 就用fastJson,并且使用那些自定義配置
*
*
*/
@RequestMapping(value = "jsonObject",method = RequestMethod.GET,produces = "application/json;charset=utf8")
@ResponseBody//告訴springmvc 把我的回傳值轉成json給用戶
public Student getStudent(){
Student student = new Student();
student.setPassword("123456");
student.setBirthday(new Date());
Teacher teacher = new Teacher();
teacher.setName("張瑞瑞");
teacher.setStudents(Arrays.asList(student));
//回圈參考
student.setTeacher(teacher);
return student;
}
@RequestMapping(value = "jsonMap",method = RequestMethod.GET,produces = "application/json;charset=utf8")
@ResponseBody//告訴springmvc 把我的回傳值轉成json給用戶
public Map<String,String> jsonMap(){
Map<String,String> objectObjectHashMap = new HashMap<>();
objectObjectHashMap.put("name","張三");
objectObjectHashMap.put("password","123456");
return objectObjectHashMap;
}
@RequestMapping(value = "jsonList",method = RequestMethod.GET,produces = "application/json;charset=utf8")
@ResponseBody//告訴springmvc 把我的回傳值轉成json給用戶
public List<Student> jsonList(){
Student student = new Student();
student.setPassword("123456");
student.setBirthday(new Date());
student.setName("張三");
Student student2 = new Student();
student2.setPassword("123456");
student2.setBirthday(new Date());
student2.setName("李四");
Student student3 = new Student();
student3.setPassword("123456");
student3.setBirthday(new Date());
student3.setName("王五");
return Arrays.asList(student,student2,student3);
}
@RequestMapping(value = "jsonArr",method = RequestMethod.GET,produces = "application/json;charset=utf8")
@ResponseBody//告訴springmvc 把我的回傳值轉成json給用戶
public Student[] jsonArr(){
Student student = new Student();
student.setPassword("123456");
student.setBirthday(new Date());
student.setName("張三");
Student student2 = new Student();
student2.setPassword("123456");
student2.setBirthday(new Date());
student2.setName("李四");
Student student3 = new Student();
student3.setPassword("123456");
student3.setBirthday(new Date());
student3.setName("王五");
return new Student[]{student,student2,student3};
}
@RequestMapping(value = "jsonDate",method = RequestMethod.GET,produces = "application/json;charset=utf8")
@ResponseBody//告訴springmvc 把我的回傳值轉成json給用戶
public Date getDate(){
return new Date();
}
@RequestMapping(value = "jsonStr",method = RequestMethod.GET,produces = "application/json;charset=utf8")
@ResponseBody//告訴springmvc 把我的回傳值轉成json給用戶
public String jsonStr(){
return "天青色等煙雨";
}
}
5.請求引數
中文請求亂碼
<!-- 配置過濾器,解決中文亂碼的問題 -->
<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>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
1.基本型別:注意使用包裝型別 避免出轉換例外
//@Controller//標記這個類要被springmvc管理
//@ResponseBody//作用在類上 相當于所有的方法都加了這個
@RestController//@ResponseBody+@Controller
public class ParamController {
//@RequestMapping(value = "",method = RequestMethod.GET)
@GetMapping("/param/param01")//RequestMapping的get請求方式
//自動拆箱---->有可能出現空指標例外
public Student param01(String name,Integer age){//name對應前端name age對應前端的age
System.out.println("接收到呼叫方傳遞的引數:"+name+","+age);
Student student = new Student();
student.setName("張三");
return student;
}
}
$(function () {
$("#ajax").click(function () {
$.ajax({
url:"/param/param01?name=李四",
type:"GET",
data:{age:10},
dataType:"json",//回傳資料型別
success:function (data) {
console.log(data);
//for(var student in data){
// console.log(data[student].name);
//}
}
})
})
})
2.接收陣列 requestparam注解
HTTP Status 400 – Bad Request:必須的引數沒有寫,或者是引數型別不對
//@RequestMapping(value = "",method = RequestMethod.GET)
@GetMapping("/param/param01")//RequestMapping的get請求方式
//自動拆箱---->有可能出現空指標例外
//不寫RequestParam的時候 如果前端沒有傳遞name 最多name接收到為null
//寫了以后 如果沒有name引數 直接報錯
//前端傳遞引數的名稱 與RequestParam的value對應 后面的引數名字都不重要了
public Student param01(@RequestParam(required = false,value = "name") String aaa,
Integer age){
System.out.println("接收到呼叫方傳遞的引數:"+aaa+","+age);
Student student = new Student();
student.setName("張三");
return student;
}
3.物件接收
//@RequestMapping(method = RequestMethod.POST)
@PostMapping("/param/param02")
//student物件里面包含了name、password屬性 所以可以
//直接把前臺傳遞的這個key的引數 放入student物件
public Student param02(Student student,String name){
System.out.println("獲得前臺的引數:"+student);
return student;
}
$("#ajax2").click(function () {
$.ajax({
url:"/param/param02?name=李四",
type:"POST",
data:{password:"123456"},
dataType:"json",//回傳資料型別
success:function (data) {
console.log(data);
//for(var student in data){
// console.log(data[student].name);
//}
}
})
})
4.@requestBody:接收前臺的json物件
415:后端希望接收到一個json物件,但是前端傳遞不是
$("#ajax3").click(function () {
var student ={
"name":"張三",
password:"123456"
}
console.log(JSON.stringify(student))
$.ajax({
url:"/param/param03",
type:"POST",//必須是post
data:JSON.stringify(student),//json字串
dataType:"json",//回傳資料型別
contentType:"application/json",//前端傳遞到后端的型別
success:function (data) {
console.log(data);
//for(var student in data){
// console.log(data[student].name);
//}
}
})
})
@PostMapping("/param/param03")
//RequestBody:告訴springmvc我要的json物件
public Student param03(@RequestBody Student student){
System.out.println("獲得前臺的引數:"+student);
return student;
}
5.集合接收
@PostMapping("/param/param04")
public List<Student> getList(@RequestBody ArrayList<Student> students){
System.out.println(students);
return students;
}
$("#ajax4").click(function () {
var student =[
{
"name":"張三",
password:"123456"
},
{
"name":"李四",
password:"123456"
}
]
$.ajax({
url:"/param/param04",
type:"POST",
data:JSON.stringify(student),//json字串
dataType:"json",//回傳資料型別
contentType:"application/json",//前端傳遞到后端的型別
success:function (data) {
console.log(data);
//for(var student in data){
// console.log(data[student].name);
//}
}
})
})
6.日期轉換
當前版本未出現日期轉換問題,如有問題配置一個日期轉換器即可(下面的代碼未測驗,應該沒問題)
<!-- 配置注解驅動,使用自定義日期轉換器 -->
<mvc:annotation-driven conversion-service="myConvert"/>
<!-- 日期轉換器 -->
<!-- 定義轉換器 -->
<bean id="myConvert" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="converters">
<set>
<!-- 自己的寫的轉換器全路徑名 -->
<bean class="com.xue.utils.MyConvert"></bean>
</set>
</property>
</bean>
package com.xue.utils;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.springframework.core.convert.converter.Converter;
/**
* 定義時間轉換器springmvc
* Converter<S, T>
* S:source要轉換的源型別
* T:target 要轉換成的資料型別
* @author
*
*/
public class MyConvert implements Converter<String, Date> {
@Override
public Date convert(String source) {
Date result = null;
try {
//指定日期的格式
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//將源資料轉為指定日期格式
result = sdf.parse(source);
} catch (ParseException e) {
e.printStackTrace();
}
//回傳轉換后的時間格式日期
return result;
}
}
6.總結
6.1后端傳遞到前臺
1.跳轉頁面
A:return ”index” 如果在springmvc.xml配置了前后綴就會默認拼接 如果沒有配置 就需要自己寫全路徑
B: return “redirect:index.html” redirect不會去拼接
無論是重定向或者跳轉都可以呼叫后臺的方法
C:modelAndView addObject()添加資料 添加的資料 放在request作用域 viewName:視圖名稱
2.回傳json
1.@ResponseBody
2.@RestController = @ResponseBody+@Controller
6.2前端傳遞到后端
1.如果是普通get請求 只需要 請求引數 與方法接收引數的名稱相同即可,物件的屬性跟請求引數相同也會自動匹配
2.傳遞陣列/集合 :
A:前端 通過key—value 比如{id:ids} @RequestParam(“id[]”) POST請求
B:前端傳遞json字串 json.stringfy() 需要配置contentType:”application/json”
后端方法:@RequestBody 名字不重要,但是都寫成相同
6.3HTTP的常見code編號
404:請求路徑錯誤
400:引數錯誤
405:請求方式 錯誤 比如后端 method=RequestMethod.POST 前端采用get請求
302:重定向
304:走瀏覽器快取
500:后臺代碼拋例外
415:json轉換問題,后臺用了requestbody
6.4注解
GetMapping、postMapping、requestParam、requestBody、responseBody、restController
7.檔案上傳
匯入jar
<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.3</version>
</dependency>
配置:
<!-- 組態檔上傳決議器 id:必須是multipartResolver
//設定決議檔案的大小,當上傳檔案大于8M時,會出錯,防止惡意攻擊占記憶體
-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="#{1024*1024*80}"/>
<property name="defaultEncoding" value="utf-8"/>
</bean>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>springmvc upload</title>
<link href="/css/bootstrap.min.css">
<script src="/js/jquery-3.3.1.min.js"></script>
<script src="/js/bootstrap.min.js"></script>
</head>
<body> <!--表單的按鈕提交檔案上傳 這兒需要enctype method必須是post
這兒是ajax可以不寫-->
<form id="uploadForm" enctype="multipart/form-data">
<input id="file" type="file" name="file" /><br>
<input id="file22" type="file" name="file" /><br>
<input type="text" name="username"/><br>
<button id="upload" type="button">upload</button>
</form>
</body>
<script>
$(function () {
$("#upload").click(function () {
$.ajax({
url: '/upload',
type: 'POST',
cache: false,
data: new FormData($('#uploadForm')[0]),
processData: false,
contentType: false,
success: function (res) {
console.log(res);
}
})
})
})
</script>
</html>
這里要注意幾點:
processData設定為false,因為data值是FormData物件,不需要對資料做處理,
<form>標簽添加enctype="multipart/form-data"屬性,
cache設定為false,上傳檔案不需要快取,
contentType設定為false,不設定contentType值,因為是由<form>表單構造的FormData物件,且已經宣告了屬性enctype="multipart/form-data",所以這里設定為false,
上傳后,服務器端代碼需要使用從查詢引數名為file獲取檔案輸入流物件,因為<input>中宣告的是name="file",
如果不是用<form>表單構造FormData物件又該怎么做呢?
2.使用FormData物件添加欄位方式上傳檔案
HTML代碼
<div id="uploadForm">
<input id="file" type="file"/>
<button id="upload" type="button">upload</button>
</div>
這里沒有<form>標簽,也沒有enctype="multipart/form-data"屬性,
javascript代碼
var formData = new FormData();
formData.append('file', $('#file')[0].files[0]);
$.ajax({
url: '/upload',
type: 'POST',
cache: false,
data: formData,
processData: false,
contentType: false
}).done(function(res) {
}).fail(function(res) {});
這里有幾處不一樣:
append()的第二個引數應是檔案物件,即$('#file')[0].files[0],
contentType也要設定為‘false’,
從代碼$('#file')[0].files[0]中可以看到一個<input type="file">標簽能夠上傳多個檔案,
只需要在<input type="file">里添加multiple或multiple="multiple"屬性,
package cn.cdqf.web;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
@RestController
public class UploadController {
@PostMapping("upload")
public Map upload(String username, String password,
@RequestParam("file") MultipartFile[] files) throws IOException {
for(MultipartFile file:files){
//獲得名稱
String originalFilename = file.getOriginalFilename();
String name = file.getName();
//暫時知道如何存盤,在專案中會有單獨服務器 到時候在處理
File file1 = new File("D://"+originalFilename);
System.out.println(file1);
file.transferTo(file1);
}
HashMap<Object, Object> objectObjectHashMap = new HashMap<>();
return objectObjectHashMap;
}
}
8.攔截器
過濾器,優于框架執行
過濾器不依賴框架,移植性比較好
request,response,filterChain
針對于現在用springmvc的情況下
可以獲得request里面所有引數,但是無法獲得要執行的controller與方法
攔截器有三個引數HttpServletRequest request, HttpServletResponse response, Object handler
handler:就可以拿到目標方法
攔截器1:
package cn.cdqf.interceptor;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class MyInterceptor implements HandlerInterceptor {
//http://localhost:8888/param/param01 ----->abc()
//會在目標方法abc()執行之前執行,如果return true那么就繼續執行目標方法,如果是false就在這里就結束
//handler:引數就可以獲得controller以及執行的目標方法,這個過濾器是拿不到的
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("攔截器1執行了...");
return true;
}
//目標方法正常執行結束后執行
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("攔截器1:目標方法正常執行結束后執行");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("攔截器1:不管有沒有例外都會執行....");
}
}
攔截器2:
package cn.cdqf.interceptor;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class MyInterceptor2 implements HandlerInterceptor {
//http://localhost:8888/param/param01 ----->abc()
//會在目標方法abc()執行之前執行,如果return true那么就繼續執行目標方法,如果是false就在這里就結束
//handler:引數就可以獲得controller以及執行的目標方法,這個過濾器是拿不到的
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("攔截器2執行了...");
return true;
}
//目標方法正常執行結束后執行
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("攔截器2:目標方法正常執行結束后執行");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("攔截器2:不管有沒有例外都會執行....");
}
}
配置:
<mvc:interceptors>
<mvc:interceptor>
<!--要攔截的路徑-->
<mvc:mapping path="/**"/>
<bean class="cn.cdqf.interceptor.MyInterceptor"></bean>
</mvc:interceptor>
<mvc:interceptor>
<!--要攔截的路徑-->
<mvc:mapping path="/**"/>
<bean class="cn.cdqf.interceptor.MyInterceptor2"></bean>
</mvc:interceptor>
</mvc:interceptors>
結果:
攔截器1執行了...
攔截器2執行了...
接收到呼叫方傳遞的引數:李四,10
攔截器2:目標方法正常執行結束后執行
攔截器1:目標方法正常執行結束后執行
攔截器2:不管有沒有例外都會執行....
攔截器1:不管有沒有例外都會執行....
9.引數校驗
前端校驗:可以減少服務器壓力,因為前端校驗了就不需要走服務器,不安全,別人有很多種方式可以跳過你的檢驗
后端校驗:安全,服務器壓力大
開發的時候應該前端+后端
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.0.7.Final</version>
</dependency>

package cn.cdqf.param;
import org.hibernate.validator.constraints.Length;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotBlank;
import java.io.Serializable;
public class User implements Serializable {
@NotBlank(message = "用戶名不能為null")
private String username;
@Min(value = 18,message = "未成年人禁止入內")
@Max(value = 35,message = "年齡太大也別來了")
private int age;
@Length(message = "長度必須在5-10之間",min = 5,max = 10)
@NotBlank(message = "地址不能為null")
private String address;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
package cn.cdqf.param;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@RestController
public class Param2Controller {
@GetMapping("param/check01")
public Map<Object,Object> check01(@Validated User user, BindingResult bindingResult){
HashMap<Object, Object> objectObjectHashMap = new HashMap<>();
if(bindingResult.hasErrors()){//引數校驗沒有過
//取出錯誤
List<FieldError> fieldErrors = bindingResult.getFieldErrors();
for(FieldError fieldError:fieldErrors){
String field = fieldError.getField();//username屬性名
String defaultMessage = fieldError.getDefaultMessage();//錯誤資訊
objectObjectHashMap.put(field,defaultMessage);
}
}
return objectObjectHashMap;
}
}
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-l2yWfawk-1607477581179)(1607331637070.png)]
public interface GroupA {
}
public interface GroupB {
}
@NotNull(message="id不能為空!",groups = {GroupA.class})
private Integer id;
@NotBlank(message="用戶名不能為空!",groups = {GroupB.class})
@Size(min=4,max=12,message="用戶名的長度在4~12之間!")
private String username;
@Validated(value= {GroupB.class})
*@Validated注解表示使用Spring的校驗機制,支持分組校驗,宣告在入參上.
*@Valid注解表示使用Hibernate的校驗機制,不支持分組校驗,宣告在入參上.
10.統一例外攔截
后臺代碼出錯了,應該給用戶回傳一個比較友好的提示,例如:程式君崩潰了
package cn.cdqf.param;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@RestController
public class Param2Controller {
@GetMapping("param/check01")
public Map<Object,Object> check01(@Validated User user, BindingResult bindingResult){
BindingResultUtil.check(bindingResult);//校驗,不應該有回傳值 不然跟業務耦合了,,
HashMap<Object, Object> objectObjectHashMap = new HashMap<>();
return objectObjectHashMap;
}
}
package cn.cdqf.param;
import java.util.Map;
public class CustomException extends RuntimeException{
private Map<Object,Object> map;
public CustomException(){
super();
}
public CustomException(Map<Object,Object> map){
super();
this.map = map;
}
public Map<Object,Object> getMap(){
return map;
}
}
package cn.cdqf.param;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import java.util.HashMap;
import java.util.List;
public class BindingResultUtil {
public static void check(BindingResult bindingResult){
HashMap<Object, Object> objectObjectHashMap = new HashMap<>();
if(bindingResult.hasErrors()){//引數校驗沒有過
//取出錯誤
List<FieldError> fieldErrors = bindingResult.getFieldErrors();
for(FieldError fieldError:fieldErrors){
String field = fieldError.getField();//username屬性名
String defaultMessage = fieldError.getDefaultMessage();//錯誤資訊
objectObjectHashMap.put(field,defaultMessage);
}
}
//沒有錯
if(objectObjectHashMap.size()==0)return;
//人為拋出例外,代碼中盡量不要去拋例外,效率低
throw new CustomException(objectObjectHashMap);
}
}
package cn.cdqf.param;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import java.util.HashMap;
import java.util.Map;
/**
* 我的例外處理器:攔截所有controller,所有controller拋出例外這個地方都能知道
* 雖然沒有配置也起效果,因為它在被掃描的包
*/
//@ControllerAdvice//增強所有controller的功能
@RestControllerAdvice//ControllerAdvice+responseBody
public class MyExceptionHandler {
@ExceptionHandler(Exception.class)//抓例外,只要有我們指定的例外就會這個注解攔到
public Map<Object,Object> exception(Exception ex){
//代碼走到這里 說明出現了在開發階段,以及測驗階段都沒有發現的例外 程式出了bug
//發郵箱給這個專案的負責人,后臺要列印日志(為了后面改bug)
return new HashMap<>();//這兒應該給用戶回傳比較友好的界面,比如:服務器奔潰了,,,
}
//攔截的是自定例外
@ExceptionHandler(CustomException.class)
public Map<Object,Object> customException(CustomException ex){
Map<Object, Object> map = ex.getMap();
return map;
}
}
11.swagger集成
這里只是入門,因為這個跟專案業務不相關,不用單獨花時間去記,后面寫專案會天天用
springfox-swagger2
springfox-swagger-ui
<!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger2 -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger-ui -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.11.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.11.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.11.0</version>
</dependency>
配置:記得掃描配置類
package cn.cdqf.swagger;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
@Configuration
@EnableSwagger2//開啟swagger支持
public class SwaggerConfig {
@Bean//物件 把這個物件交給spring管理
public Docket api() {
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.any()) //顯示所有類
//.apis(RequestHandlerSelectors.withClassAnnotation(Api.class)) //只顯示添加@Api注解的類
.build()
.apiInfo(apiInfo());
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("軍哥測驗swagger") //粗標題
.description("java2007測驗,有問題請撥打電話1888888888") //描述
.version("1.0.0") //api version
.termsOfServiceUrl("http://xxx.xxx.com")
.license("LICENSE") //鏈接名稱
.licenseUrl("http://xxx.xxx.com") //鏈接地址
.build();
}
}
簡單使用:
package cn.cdqf.swagger;
import cn.cdqf.pojo.Student;
import io.swagger.annotations.*;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@Api("swagger測驗controller")
public class SwaggerController {
@GetMapping("swagger")
@ApiOperation(value = "swagger測驗介面")
public Student swagger(
String username,
String password){
Student student = new Student();
student.setName(username);
student.setPassword(password);
return student;
}
}
配置swagger界面放過:
<!-- swagger靜態資源訪問配置 -->
<mvc:resources mapping="swagger-ui.html" location="classpath:/META-INF/resources/" />
<mvc:resources mapping="/webjars/**" location="classpath:/META-INF/resources/webjars/" />
訪問:
http://localhost:xxxx/swagger-ui.html
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/232465.html
標籤:java
