Mvc:软件设计架构,解除v层的耦合,希望只写一套后台代码,就可以满足各种v端
1.接受前台或者其它服务的数据,并校验 json
2.返回数据给前端或者其它服务 json,流
3.指定跳转的页面或者其它服务 重定向或者跳转
数据接口
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>
<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">
<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>
<mvc:annotation-driven>mvc:annotation-driven>
beans>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<servlet>
<servlet-name>dispatcherServletservlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
<init-param>
<param-name>contextConfigLocationparam-name>
<param-value>classpath:springmvc.xmlparam-value>
init-param>
<load-on-startup>1load-on-startup>
servlet>
<servlet-mapping>
<servlet-name>dispatcherServletservlet-name>
<url-pattern>/url-pattern>
servlet-mapping>
<servlet-mapping>
<servlet-name>defaultservlet-name>
<url-pattern>*.htmlurl-pattern>
servlet-mapping>
web-app>
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了
后面的springmvc源码学习还会详细的学习这块
初始化容器的时候,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(视图解析)------>前端
@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/";
}
}
注: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>
<mvc:annotation-driven>mvc:annotation-driven>
<mvc:annotation-driven>
<mvc:message-converters register-defaults="false">
<bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter"/>
<bean class="org.springframework.http.converter.BufferedImageHttpMessageConverter"/>
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<constructor-arg value="UTF-8"/>
bean>
<bean class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter">
<property name="defaultCharset" value="UTF-8"/>
<property name="supportedMediaTypes">
<list>
<value>text/html;charset=UTF-8value>
<value>application/jsonvalue>
list>
property>
<property name="fastJsonConfig" ref="fastJsonConfig"/>
bean>
mvc:message-converters>
mvc:annotation-driven>
<bean id="fastJsonConfig" class="com.alibaba.fastjson.support.config.FastJsonConfig">
<property name="charset" value="UTF-8"/>
<property name="serializerFeatures">
<list>
<value>WriteNullListAsEmptyvalue>
<value>WriteDateUseDateFormatvalue>
<value>PrettyFormatvalue>
<value>WriteMapNullValuevalue>
<value>WriteNullStringAsEmptyvalue>
<value>DisableCircularReferenceDetectvalue>
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>
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 "天青色等烟雨";
}
}
<filter>
<filter-name>characterEncodingFilterfilter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilterfilter-class>
<init-param>
<param-name>encodingparam-name>
<param-value>UTF-8param-value>
init-param>
filter>
<filter-mapping>
<filter-name>characterEncodingFilterfilter-name>
<url-pattern>/*url-pattern>
filter-mapping>
//@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);
//}
}
})
})
})
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;
}
//@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);
//}
}
})
})
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;
}
@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);
//}
}
})
})
当前版本未出现日期转换问题,如有问题配置一个日期转换器即可(下面的代码未测试,应该没问题)
<!-- 配置注解驱动,使用自定义日期转换器 -->
<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: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;
}
}
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
1.如果是普通get请求 只需要 请求参数 与方法接收参数的名称相同即可,对象的属性跟请求参数相同也会自动匹配
2.传递数组/集合 :
A:前端 通过key—value 比如{id:ids} @RequestParam(“id[]”) POST请求
B:前端传递json字符串 json.stringfy() 需要配置contentType:”application/json”
后端方法:@RequestBody 名字不重要,但是都写成相同
404:请求路径错误
400:参数错误
405:请求方式 错误 比如后端 method=RequestMethod.POST 前端采用get请求
302:重定向
304:走浏览器缓存
500:后台代码抛异常
415:json转换问题,后台用了requestbody
GetMapping、postMapping、requestParam、requestBody、responseBody、restController
导入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>
配置:
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="#{1024*1024*80}"/>
<property name="defaultEncoding" value="utf-8"/>
bean>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>springmvc uploadtitle>
<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>
<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">uploadbutton>
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">uploadbutton>
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;
}
}
过滤器,优于框架执行
过滤器不依赖框架,移植性比较好
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:不管有没有异常都会执行....
前端校验:可以减少服务器压力,因为前端校验了就不需要走服务器,不安全,别人有很多种方式可以跳过你的检验
后端校验:安全,服务器压力大
开发的时候应该前端+后端
<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;
}
}
校验组
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的校验机制,不支持分组校验,声明在入参上.
后台代码出错了,应该给用户返回一个比较友好的提示,例如:程序君崩溃了
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
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;
}
}
这里只是入门,因为这个跟项目业务不相关,不用单独花时间去记,后面写项目会天天用
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界面放过:
<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.bilibili.com/video/BV1ra411F7Er/
https://www.bilibili.com/video/BV18Z4y1g7Si/