1、SpringMVC传参的七种方式(前端传给后端)
1)基本方式传参
@PostMapping("/addDept")
//方式一:基本方式传参:参数的名字和表单标签及url的名字一致即可
public String addDept(int dno,String name,String loc){
//如何接收表单里的值 看上边方法的参数
Dept dept = new Dept(dno,name,loc);
System.out.println(dept);
//默认转发跳转
return "index";
}
2)对象传参
@PostMapping("/addDept2")
//方式二:对象传参:表单标签或URL的参数名和对象的属性名一致即可
public String addDept2(Dept dept){
System.out.println(dept);
//默认转发跳转 forward:走视图解析器
//重定向跳转 redirect:不走视图解析器 //需要确定页面的路径和扩展名
// return "index";
return "redirect:/index.jsp";
}
3)数组传参
@PostMapping("/addStudent")
//数组传参
public String register(String stuNo,String stuName,String[] hobby){
Student student = new Student(stuNo,stuName,hobby);
System.out.println(student);
return "index";
}
4)注解传参
@PostMapping("/addStudent2")
//注解方式 官方推荐
public String register2(@RequestParam(name = "stuNo") String sNo,
@RequestParam(name = "stuName") String name,
@RequestParam(name = "hobby",required = false,defaultValue = "")
String[] hob){
//name 表单或url的标签或变量的名字
//required 是否必须传递这个参数 false不是 默认为true
//defaultValue 当没有传递这个参数时,默认值就是defaultValue设定的值
Student stu = new Student();
stu.setStuNo(sNo);
stu.setStuName(name);
stu.setHobby(hob);
System.out.println(stu);
return "index";
}
@GetMapping("/test")
public String test(@RequestParam(name = "id") int testId,
@RequestParam(name = "desc", required = true,defaultValue = "456") String des){
System.out.println("id=" + testId +",desc=" + des);
return "index";
}
5)集合传参
get方法
Controller:
@Controller
@RequestMapping("/teacher")
public class TeacherController {
//集合传参
@GetMapping("/add")
public String addTeacher(Teacher teacher){
System.out.println(teacher);
return "index";
}
}
url:
http://localhost:8080/springmvcpro/teacher/add?teaName=zhaoyiyi&studentList[0].stuNo=001&studentList[0].stuName=wangyi&
studentList[0].hobby[0]=sing&studentList[0].hobby[1]=run&studentList[1].stuNo=002&
studentList[1].stuName=wangeri&studentList[1].hobby[0]=cook&
studentList[1].hobby[1]=sleep
post方法
Controller
package com.qf.springmvcpro.controller;
import com.qf.springmvcpro.pojo.Student;
import com.qf.springmvcpro.pojo.Teacher;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("/teacher")
public class TeacherController {
@PostMapping("/add2")
public String addTeacher2(Teacher teacher){
System.out.println("老师姓名:"+teacher.getTeaName());
System.out.println("学生如下:");
for(Student stu : teacher.getStudentList()){
System.out.println(stu);
}
return "index";
}
}
jsp:
<%--
Created by IntelliJ IDEA.
User: poison
Date: 2022/4/14
Time: 21:07
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<form method="post" action="teacher/add2">
<p>讲师姓名:<input type="text" name="teaName"/></p>
<%--这就是一个节点--%>
<div class="divStudent">
<p>学生学号:<input type="text" name="studentList[0].stuNo"/></p>
<p>学生姓名:<input type="text" name="studentList[0].stuName"/></p>
</div>
<hr/>
<%--另一个节点--%>
<div class="divStudent">
<p>学生学号:<input type="text" name="studentList[1].stuNo"/></p>
<p>学生姓名:<input type="text" name="studentList[1].stuName"/></p>
</div>
<hr/>
<%--另一个节点--%>
<div class="divStudent">
<p>学生学号:<input type="text" name="studentList[2].stuNo"/></p>
<p>学生姓名:<input type="text" name="studentList[2].stuName"/></p>
</div>
<p><input type="submit" value="添加讲师"/></p>
</form>
</body>
</html>
6)路径传参
使用Restful风格编程
package com.qf.springmvcpro.controller;
import com.qf.springmvcpro.pojo.Dept;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
@Controller
@RequestMapping("/dept") //加两级路径 不区分请求方式 是get还是post get和post都可以
public class DeptController {
//{}里边的名字可随意填写 和下边@PathVariable("dno") 对应即可
@GetMapping("/addDept3/{dno}/{name}/{loc}")
//括号前边的是 @GetMapping("/addDept3//{duno},{name},{loc}") 中{}里的名字
//括号后边的是给pojo赋值的变量名 可以随意起名
//类型和pojo相同
public String addDept3(@PathVariable("dno") int deptNo,
@PathVariable("name") String dName,
@PathVariable("loc") String loc){
Dept dept = new Dept(deptNo,dName,loc);
System.out.println(dept);
return "index";
}
}
url
http://localhost:8080/springmvcpro/dept/addDept3/9093/zhangsn/beijing
7)Json传参
前端页面
function addDept() {
//声明一个JSON数据
//【注意】json的key要和后台java对象的属性名要相同,否则传递错误
var json1={"deptNo":9050,"dName":"开发部","loc":"设计城"};
//把JSON转成字符串
var strJson=JSON.stringify(json1);
$.ajax({
url:"dept/add4.action",
type:"post",
dataType:"text",//得到的数据类型是字符串
contentType:"application/json", //【***注意***】告知服务器传递的是JSON
async:true,
data:strJson,//传递数据
success:function (result) {
if(result=="true"){
alert("添加成功!");
}else{
alert("添加失败!");
}
}
});
}
控制器
//前端传递JSON
@PostMapping("/add4.action")
@ResponseBody
public String addDept4(@RequestBody Dept dept){
//@RequestBody 把前端传递的JSON转成对象
System.out.println("前端传递数据:"+dept);
return "true";
}
2、SpringMVC的五种收参方式(后端传给前端)
在没有使用SpringMVC时,传值方式:
1)使用作用域 优先使用request session
使用request作用域存值,必须要转发到视图
使用sesson作用域存值,转发、重定向都可以
实现步骤:
导入需要的jar
<!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.servlet.jsp/jsp-api -->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.1</version>
<scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.servlet/jstl -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
使用作用域存储数据
@GetMapping("/find")
public String findDept(HttpServletRequest request){
List<Dept> list=new ArrayList<Dept>();
Dept dept1=new Dept(9091,"1部","大连");
Dept dept2=new Dept(9092,"2部","北京");
list.add(dept1);
list.add(dept2);
//如何把数据传递给deptlist.jsp页面
request.setAttribute("data",list);
//转发
return "deptlist";
}
视图获取数据
<html>
<head>
<title>部门列表</title>
</head>
<body>
<table>
<tr>
<td>部门编号</td>
<td>部门名称</td>
<td>部门位置</td>
</tr>
<c:forEach items="${requestScope.data}" var="dept">
<tr>
<td>${dept.deptNo}</td>
<td>${dept.dName}</td>
<td>${dept.loc}</td>
</tr>
</c:forEach>
</table>
</body>
</html>
2)Model传值
//使用Model传值给视图
@GetMapping("/find1")
public String findDept1(Model model){
List<Dept> list=new ArrayList<Dept>();
Dept dept1=new Dept(9093,"3部","大连");
Dept dept2=new Dept(9094,"4部","北京");
list.add(dept1);
list.add(dept2);
//把数据存入到Model
model.addAttribute("data",list); //本质还是使用request进行传递
return "deptlist";
}
前端获取数据方式不变
3)ModelAndView传值
//使用ModelAndView传值
@GetMapping("/find2")
public ModelAndView findDept2(){
List<Dept> list=new ArrayList<Dept>();
Dept dept1=new Dept(9093,"3部","大连");
Dept dept2=new Dept(9094,"4部","北京");
list.add(dept1);
list.add(dept2);
//创建ModelAndView对象
ModelAndView modelAndView=new ModelAndView();
//设置视图的名字
modelAndView.setViewName("deptlist");
//赋值数据
modelAndView.addObject("data",list);
//视图解析器解析modelAndView
return modelAndView;
}
前端获取数据方式不变
4)@SessionAttributes 传值
本质就是使用session进行传值
5)json传值
控制器得到数据,对象,需要把集合转成JSON
原来: FastJson----手动添加依赖,进行转换
使用框架后,SpringMVC通过注解@ResponseBody把返回的数据,转成JSON格式的字符串
@ResponseBody使用Jackson进行转换
添加jackson的jar依赖
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.8</version>
</dependency>
前端页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script type="text/javascript" src="js/jquery-3.4.1.min.js"></script>
<script>
function getDepts() {
//发出AJAX请求
$.ajax({
url:"dept/find4.action",
type:"get",
dataType:"json",
async:true,
success:function (jsonData) {
var str=JSON.stringify(jsonData);
alert(str);
}
});
}
</script>
</head>
<body>
<input type="button" value="获取部门数据" onclick="getDepts()"/>
</body>
</html>
控制器
@GetMapping("/find4.action")
@ResponseBody //1、把返回的数据转成JSON,在核心核心控制器进行转换 2、不走视图解析器
public List<Dept> findDept4(){
//方法返回的字符串在控制器里默认是转发或重定向的视图名
List<Dept> list=new ArrayList<Dept>();
Dept dept1=new Dept(9091,"1部","大连");
Dept dept2=new Dept(9092,"2部","北京");
list.add(dept1);
list.add(dept2);
return list;
}
概念:Handler 在控制器中,请求的路径以及对应的方法统称为Handler
@GetMapping("/find5.action")
public @ResponseBody List<Dept> findDept5(){
List<Dept> list=new ArrayList<Dept>();
Dept dept1=new Dept(9091,"1部","大连");
Dept dept2=new Dept(9092,"2部","北京");
list.add(dept1);
list.add(dept2);
return list;
}
问题:如果控制器中所有的方法都返回JSON格式的字符串,每个方法都添加@ResponseBody 比较繁琐
解决:使用@RestController注解
@RestController=@Controller+@ResoponseBody
package com.qf.springmvcpro.controller;
import com.qf.springmvcpro.pojo.Dept;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.List;
@RestController
@RequestMapping("/dept2")
public class DeptController2 {
@GetMapping("/find1.action") //无需添加@ResponseBody
public List<Dept> findDept1(){
List<Dept> list=new ArrayList<Dept>();
Dept dept1=new Dept(9091,"1部","大连");
Dept dept2=new Dept(9092,"2部","北京");
list.add(dept1);
list.add(dept2);
return list;
}
@GetMapping("/find2.action")
public Dept findDept2(){
Dept dept2=new Dept(9092,"2部","北京");
return dept2;
}
}
【说明】如果方法本身就是字符串,则不需要JSON转换
//如果数据本身就已经是字符串,无需使用@ResponseBody注解进行转换
@GetMapping(value = "/test.action",produces = "text/html;charset=utf-8")
@ResponseBody
public String test(){
return "你好!";
}
3、中文乱码解决
SpringMVC框架自带了过滤器,拦截所有请求,以及响应,进行编码设置
在web.xml文件中进行配置
<filter>
<filter-name>codingSet</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<!--告知CharacterEncodingFilter过滤器,我们需要设置的编码方式-->
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>codingSet</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
4、转发、重定向
转发:默认就就是转发 retrun "forward:index";
重定向: return ”redirect:/index.jsp“;
【说明】
1、需要指定路径和扩展名
2、重定向不走视图解析器
使用的时候有选择:
1、为了防止因刷新而产生的url或表单的重复提交,添加、修改、删除后,使用重定向进行页面跳转
2、查询之后可以使用转发
5、在SpringMVC框架下,静态资源处理
静态资源:html页面 css样式 图片等资源 JavaScript代码
问题:当请求静态资源的时候,tomca拦截静态请求到DispacherServlet中,检索Controller中有无对应的请求路径,如果有,则调用对应的方法,如果没有抛404异常。
解决方案:
1、由于DispacherServlet拦截静态的请求,并没有放行,通过配置让其对静态资源放行,放行给tomcat处理静态资源的servlet, DefaultServlet
在springMVC的配置文件中
<!--对静态资源的请求放行,放行给DefaultServlet
DefaultServlet就回调到对应路径下寻找静态资源,响应给用户
-->
<mvc:default-servlet-handler></mvc:default-servlet-handler>
2、在拦截请求的时候不使用/ 而使用后缀的方式
<servlet-mapping>
<servlet-name>servlet</servlet-name>
<url-pattern>*.action</url-pattern>
</servlet-mapping>
@GetMapping("/find3.action")
public String findDept3(Model model){
List<Dept> list=new ArrayList<Dept>();
Dept dept1=new Dept(9093,"3部","大连");
Dept dept2=new Dept(9094,"4部","北京");
list.add(dept1);
list.add(dept2);
//使用model存值
model.addAttribute("data1",list); //存入session中
model.addAttribute("data2",dept1); //存入到session中
return "deptlist";
}
只拦截以action为结尾的请求,到DispacherServlet,别的请求不拦截,最终到达DefaultServlet里
6、JACKSON常用注解
@JsonIgnore:忽略,对应的属性不会被序列化成json数据
private int deptNo;
private String dName;
@JsonIgnore //告知JackSon在转成json数据时,忽略掉当前属性
private String loc;
@JsonProperty 序列化成json数据时,json的key的别名
@JsonProperty("dno")
private int deptNo;
@JsonProperty("name")
private String dName;
@JsonFormat 对默认的时间类型进行格式化
pattern:时间格式 timezone:时区 东八时区
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
private Date date;
String str="";
if(str.length==0){}
@JsonInclude null值的属性不会序列化成json数据
Include.NON_DEFAULT 属性为默认值不序列化 (例如int为0,Object为null)
Include.NON_EMPTY 属性为 空("") 或者为 NULL 都不序列化
Include.NON_NULL 属性为NULL 不序列化
@JsonInclude(JsonInclude.Include.NON_NULL) //null值的属性就不会被序列化成JSON数据
//@JsonInclude(JsonInclude.Include.NON_EMPTY) //"".lentgh==0 或null值的属性也不会被序列化成JSON数据
private String desc;
@JsonSerialize 用于在序列化时嵌入我们自定义的代码
//声明总薪资的属性
//使用了自定义的序列化属性
@JsonSerialize(using = MySerializable.class)
private Double salary=10000.126;
package com.qf.springmvcpro.util;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import java.io.IOException;
import java.math.BigDecimal;
public class MySerializable extends JsonSerializer<Double> {
public void serialize(Double value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
//参数value,就是属性的值
//将属性值 小数位数保留两位,然后四舍五入
String number= BigDecimal.valueOf(value).setScale(2,BigDecimal.ROUND_HALF_UP).toString();
//将转换后的值进行输出---转成json的数据值
gen.writeNumber(number);
}
}
7、FastJson的使用及常用注解
@ResponseBody,默认使用jackson ,可以用fastjson进行替换
1、添加fastjson的依赖
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.54</version>
</dependency>
2、通过springMVC的配置文件的配置,使用fastjson替换掉jackson
<!--使用fastjson替换掉jackson-->
<mvc:annotation-driven>
<!--安装FastJson转换器-->
<mvc:message-converters>
<bean class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter">
<!--告知fastjson 转换的类型 json-->
<property name="supportedMediaTypes">
<list>
<value>application/json</value>
</list>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
3、使用FastJson
【说明】@ResponseBody @ReauestBody @RestController 使用与之前使用jackson时没有任何区别
FastJson的注解与Jackson不同
@JSONField 格式化
@JSONField(format = "yyyy-MM-dd hh:mm:ss") //格式化
private Date date;
@JSONField 别名
@JSONField(name = "name") //别名
private String dName;
@JSONField 忽略掉空值及""(“” 双引里边没有值)
@JSONField(serialzeFeatures = SerializerFeature.WriteNullStringAsEmpty)//忽略掉空值及“”
private String desc;
@JSONField 被忽略
@JSONField(serialize = false) //被忽略
private String loc;
@JSONField 使用自定义序列化属性
@JSONField(serializeUsing = MapSerializer.class) //使用自定义序列化属性
private Double totalSal=10000.126;
8、异常解析器
异常处理原则:dao 有异常时,向上抛
service 有异常时,继续向上抛
controller 有异常时,捕获
如果controller中的每个handler方法都进行异常捕获的话,代码冗余、繁琐,使用springMVC的异常解析器来简化异常捕获
异常解析器的设计思想:每个handler发生异常后,抛出异常,异常集中抛给异常解析器,异常解析器,对异常同一处理,简化了异常处理
编码:
1、根据不同的异常,创建不同的显示页面
2、定义异常解析器
package com.qf.springmvcpro.util;
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.IOException;
public class MyExceptionResolver implements HandlerExceptionResolver {
//handler方法中的异常都跑到此类的下面方法中
public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {
//同一处理异常
//打印堆栈上的异常信息
e.printStackTrace();
ModelAndView modelAndView=new ModelAndView();
//判断异常类型,不同异常,跳转到不同页面
if(e instanceof NullPointerException){
modelAndView.setViewName("redirect:/err/null.jsp");
}else if(e instanceof NumberFormatException){
modelAndView.setViewName("redirect:/err/format.jsp");
}else if(e instanceof IOException){
modelAndView.setViewName("redirect:/err/io.jsp");
}else{
modelAndView.setViewName("redirect:/err/exception.jsp");
}
return modelAndView;
}
}
3、注册异常解析器
在springmvc的配置文件中
<!--注册异常解析器-->
<bean class="com.qf.springmvcpro.util.MyExceptionResolver"></bean>
4、handler的方法中抛出异常即可
package com.qf.springmvcpro.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/test")
public class ExceptionController {
@GetMapping("/test1.action")
public String test1() throws NullPointerException{
String str=null;
System.out.println(str.length());
return "success";
}
@GetMapping("/test2.action")
public String test2() throws NumberFormatException{
String str="a";
int num=Integer.parseInt(str);
System.out.println(num);
return "success";
}
}
原理:springmvc捕获抛出的所有异常,执行代理对象(异常处理器),统一处理
9、拦截器
概念:拦截特定的请求,转移到类中,执行特定的方法,这个类就称为拦截器
SpringMVC的拦截器,在handler方法执行之前、或之后执行的方法,减少handler方法中的代码冗余
时间点:在handler之前
之后
1、定义拦截器
package com.qf.springmvcpro.interceptor;
import org.springframework.lang.Nullable;
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 {
//在执行handler方法之前执行
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("执行拦截器的前置方法");
//true:请求继续向下发出,去执行handler方法
//false:请求中断
return true;
}
//在handler方法执行之后:进一步的响应
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
System.out.println("执行拦截器的后置方法");
}
//在handler方法执行之后:在资源回收时
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
System.out.println("执行拦截器的after");
}
}
2、配置拦截路径
<!--配置拦截路径-->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/*.action"/>
<!--刨除以下请求路径-->
<mvc:exclude-mapping path="/dept2/*.action"/>
<bean class="com.qf.springmvcpro.interceptor.MyInterCeptor"></bean>
</mvc:interceptor>
</mvc:interceptors>
【说明】作用,为了提取handler中的冗余代码
使用场景:执行权限
认证---登录
10、文件的上传
1、添加jar
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.3</version>
<exclusions>
<exclusion>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
</exclusion>
</exclusions>
</dependency>
2、上传页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form method="post" enctype="multipart/form-data" action="file/upload">
<p>文件:<input type="file" name="source"/></p>
<p><input type="submit" value="上传"/></p>
</form>
</body>
</html>
3、配置文件上传解析器
<!--文件上传解析器
【说明】文件上传解析器的id必须是multipartResolver
-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!--配置:文件的最大限制 单位是byte查出后抛出MaxUploadSizeExceededException异常 -->
<property name="maxUploadSize" value="102410000"></property>
</bean>
4、handler方法
package com.qf.springmvcpro.controller;
import org.apache.commons.io.FilenameUtils;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpSession;
import java.io.File;
import java.io.IOException;
import java.util.UUID;
@Controller
@RequestMapping("/file")
public class FileController {
@PostMapping("/upload.action")
public String upload(String userName, MultipartFile source, HttpSession session) throws IOException {
//获取文件的原始名称
String fileName=source.getOriginalFilename();
//唯一名称
String unique= UUID.randomUUID().toString();
//获取文件的后缀
String ext= FilenameUtils.getExtension(fileName);
//新名字
String newName=unique+"."+ext;
System.out.println("文件的新名字:"+newName);
//获取文件的类型
String type=source.getContentType();
System.out.println("文件的类型:"+type);
//把相对路径转换成物理路径
String realPath=session.getServletContext().getRealPath("/upload_file");
System.out.println("物理路径:"+realPath);
//文件上传
File file=new File(realPath+"\\"+newName);
source.transferTo(file);
return "index";
}
}
【注意】target下是否存在upload_file这个路径,如果不存在则手动创建
文件的大小如果查过文件上传解析器的限制,则抛出MaxUploadSizeExceededException异常
11、文件下载
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<a href="file/download.action?name=2.png">下载</a>
</body>
</html>
@GetMapping("/download.action")
public void downLoad(String name, HttpSession session, HttpServletResponse response) throws IOException {
System.out.println("要下载的文件名:"+name);
//找到下载路径
String path=session.getServletContext().getRealPath("/upload_file");
//完整的下载路径
String realPath=path+"\\"+name;
//设置响应头信息
response.setHeader("content-disposition","attachment;filename="+name);
//读取的同时写入客户端
IOUtils.copy(new FileInputStream(realPath),response.getOutputStream());
//return "index";
}
【说明】把图片上传到服务器的某个路径下,造成一个问题就是,当Tomcat重启或关闭后,清理自己的目录
存储路径不在项目下即可
12、验证码
作用:防止暴力操作,输入的验证码必须和生成的验证码(同时存于session中)要一致,如果不一致,则不进一步进行操作
场景:注册、登录
验证的实现思路:是一张图片(固定尺寸)
声明一个数组 char[] ary{'2','3'} 8个数字、字母,刨除掉 不易分辨 汉字
随机生成干扰点 干扰线
重要:随机选取指定个数的字符,画到图片的同时,存入session
【说明】数据库并不存储,
1、引入验证码jar
<dependency>
<groupId>com.github.penggle</groupId>
<artifactId>kaptcha</artifactId>
<version>2.3.2</version>
<exclusions>
<exclusion>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
</exclusion>
</exclusions>
</dependency>
2、配置验证码信息,在web.xml文件中配置
<!--配置验证码信息-->
<servlet>
<servlet-name>kap</servlet-name>
<servlet-class>com.google.code.kaptcha.servlet.KaptchaServlet</servlet-class>
<!--验证码图片的边框-->
<init-param>
<param-name>kaptcha.border</param-name>
<param-value>no</param-value>
</init-param>
<!--验证码的长度-->
<init-param>
<param-name>kaptcha.textproducer.char.length</param-name>
<param-value>5</param-value>
</init-param>
<!--验证码的组成字符-->
<init-param>
<param-name>kaptcha.textproducer.char.string</param-name>
<param-value>23456789abcdefghjkmnpqrstuvwxyzABCDEFGHJKMNPQRSTUVWXYZ</param-value>
</init-param>
<!--设置存入session后,session的key-->
<init-param>
<param-name>kaptcha.session.key</param-name>
<param-value>checkcode</param-value>
</init-param>
<!--设置背景-->
<init-param>
<param-name>kaptcha.background.clear.to</param-name>
<param-value>210,233,240</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>kap</servlet-name>
<url-pattern>/kaptcha</url-pattern>
</servlet-mapping>
3、在页面上应用验证码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>用户注册</title>
<script src="js/jquery-3.4.1.min.js"></script>
<script type="text/javascript">
//动态获取添加事件
$(function () {
$("#cap").click(function () {
//刷新验证码
var path=$(this).attr("src")+"?"+new Date().getTime();
$(this).attr("src",path);
});
});
</script>
</head>
<body>
<form method="post" action="user/reg.action">
<p>账号:<input type="text" name="userId" /></p>
<p>名称:<input type="text" name="userName" /></p>
<p>验证码:<input type="text" name="code" />
<img src="kaptcha" title="看不清,单击换一张" style="width: 100px; height: 30px" id="cap">
</p>
<p><input type="submit" value="注册"/></p>
</form>
</body>
</html>
4、handler中
package com.qf.springmvcpro.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpSession;
@Controller
@RequestMapping("/user")
public class UserController {
@PostMapping("/reg.action")
public String register(String userId, String userName, String code, HttpSession session){
//先判断验证码是否输入正确
//取出session中存储的验证码
String sessionCode=(String) session.getAttribute("checkCode");
if(code.equals(sessionCode)){
System.out.println("验证码正确");
//调用service
return "index";
}else{
System.out.println("验证码错误");
System.out.println("生成的验证码:"+sessionCode+",输入的验证码:"+code);
return "redirect:/err/exception.jsp";
}
}
}
13、RESTFUL
有两个要求:
1、请求资源唯一
在类的上方加RequestMapping
使用路径传参
2、不同的操作请求,对应不同的method
查询:get
添加:post
修改:put
删除:delete
【说明】返回的都是JSON字符串
14、跨域
新建前端项目,请求当前java项目的内容:http://localhost:8081/springmvcpro/dept2/find1.action
前端页面
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<script type="text/javascript" src="js/jquery-3.4.1.min.js"></script>
<script>
$(function(){
//发出AJAX请求
$.ajax({
type:"get",
url:"http://localhost:8081/springmvcpro/dept2/find1.action",
async:true,
dataType:"json",
success:function(jsonData){
alert(JSON.stringify(jsonData));
}
});
})
</script>
</head>
<body>
</body>
</html>
请求路径:
http://127.0.0.1:8020/pro210502/index.html
报错:
报错原因分析:
浏览器为了安全考虑,有同源策略,当前浏览器服务的协议、域名(IP)、端口号,和AJAX所请求的服务中的协议、域名、端口号中有任何一个不同的,则AJAX请求正常发出,但是拒绝接收响应。
域=协议+IP+端口号
解决方案:
1、@CrossOrigin,在后台,添加信任,允许某个域进行跨域请求
2、在前端设置允许跨域,前后端分离后,不会把前端的cookie传入到后台
设置允许携带cookie
跨项目路径要写完整
15、SpringMVC的请求流程---重要
1、在web.xml拦截所有请求,把请求拦截到DispatcherServlet中
2、DispatcherServlet在创建后,读取SpringMVC的配置文件
3、DispatcherServlet在创建后,到IoC容器中,寻找Controller对象,使用RequestMapping中的url为key,使用Controller对象作为Value值,把Controller对象存入map集合中,当请求到达后,通过url找到对应的Controller对象,称为HandlerMapping,
4、HandlerAdapter 适配,通过url拼接的方式,找Controller中对应的方法
5、 先执行拦截器 然后执行对应的handler方法(参数绑定过程) 再执行拦截器
6、生成ModelAndView :存数据,视图名等 返回到DispatcherServlet中
7、通过视图解析器ViewResolver找到视图
8、解析Model里的数据,渲染到视图上
9、响应到客户端
总结:
@Autowired是调用bean工厂中的对象
@Bean 是往bean工厂中创建对象