-
- enctype必须是 multipart/form-data
<form action="/mvc/book/doUpload1" method="post" enctype="multipart/form-data"><p><input type="file" name="img_url"></p><p><input type="submit" value="上传"></p></form>
@AutowiredHttpServletRequest request;@PostMapping("/doUpload1")@ResponseBodypublic String doUpload1() throws ServletException, IOException {//获取Request对象//getPart(页面表单提交中,获取name=img_url的值Part part = request.getPart("img_url");//文件存哪里//D:\webFolder\mvcdemo1\target\mvcdemo\String realPath = request.getServletContext().getRealPath("/");//D:\webFolder\mvcdemo1\target\mvcdemo\/imgs/String basePath = realPath + "/imgs/";System.out.println(basePath);//文件夹是否存在File baseFile = new File(basePath);if (!baseFile.exists()){baseFile.mkdirs();}//文件名String fileName = part.getSubmittedFileName();part.write(basePath + fileName);return "success";}
多文件
multiple属性
<form action="/mvc/book/doUpload2" method="post" enctype="multipart/form-data"><p><input type="file" name="img_url" multiple></p><p><input type="submit" value="上传"></p></form>
@PostMapping("/doUpload2")@ResponseBodypublic String doUpload2() throws ServletException, IOException {//获取 所有的文件Collection<Part> parts = request.getParts();String realPath = request.getServletContext().getRealPath("/imgs/");System.out.println(realPath);File realFile = new File(realPath);if (!realFile.exists()){realFile.mkdirs();}parts.forEach(part -> {String fileName = part.getSubmittedFileName();try {part.write(realPath + fileName);} catch (IOException e) {//不处理异常,仅仅是打印看看e.printStackTrace();}});return "success";}
MVC方式上传文件
- 引入依赖
<dependency><groupId>commons-fileupload</groupId><artifactId>commons-fileupload</artifactId><version>1.2.1</version></dependency><dependency><groupId>commons-io</groupId><artifactId>commons-io</artifactId><version>1.4</version></dependency>
- mvc.xml
<!--上传文件的配置--><bean class="org.springframework.web.multipart.commons.CommonsMultipartResolver"><property name="defaultEncoding" value="utf-8"/></bean>
单文件
//img_url表单提交中的name属性@PostMapping("/doUpload3")@ResponseBodypublic String doUpload3(MultipartFile img_url) throws IOException {//文件名String fileName = img_url.getOriginalFilename();//获取保存路径String realPath = request.getServletContext().getRealPath("/imgs/");System.out.println(realPath);File realFile = new File(realPath);if (!realFile.exists()){realFile.mkdirs();}//文件对象.transferTo(存储的位置+文件名)img_url.transferTo(new File(realPath + fileName));return "success";}
多文件
@PostMapping("/doUpload4")@ResponseBodypublic String doUpload4(MultipartFile[] img_url) throws IOException {if (img_url.length > 0){for (MultipartFile file : img_url){file.transferTo(new File(getFileName(file)));}}return "success";}private String getFileName(MultipartFile file){//文件名String fileName = file.getOriginalFilename();//获取保存路径String realPath = request.getServletContext().getRealPath("/imgs/");File realFile = new File(realPath);if (!realFile.exists()){realFile.mkdirs();}return realPath + fileName;}
文件下载
默认情况下,mvc框架,无法识别静态资源文件的
超链接下载
<ul><li><a href="/mvc/save/test1.docx">word文档</a></li><li><a href="/mvc/save/test2.jpg">图片</a></li><li><a href="/mvc/save/test3.pdf">PDF</a></li><li><a href="/mvc/save/test4.rar">压缩文件</a></li><li><a href="/mvc/save/test5.xlsx">Excel</a></li></ul>
如果这个文件,浏览支持,可以打开,就会直接在浏览器中打开,不进行下载
如果这个文件,浏览器无法打开,跳出下载页面
好处:简单,易学.写一个url地址超链接即可
坏处:仅能让部分格式的文件下载
流下载
这个下载 ,要经过服务器,让服务器写出文件流 给浏览器,触发下载
- ResponseEntity
@AutowiredHttpServletRequest request;@GetMapping("/test1")public ResponseEntity<byte[]> download(String name) throws IOException {//获取文件路径String realPath = request.getServletContext().getRealPath("/save/");//文件的全路径String allPath = realPath + name;//获取下载需要的文件流信息FileInputStream inputStream = new FileInputStream(allPath);//获取流的数组byte[] buffer = new byte[inputStream.available()];//读取inputStream.read(buffer);//文件下载的时候,显示的名字,需要改文件名了,再修改//设置响应的头信息,告诉浏览器,返回的是文件HttpHeaders httpHeaders = new HttpHeaders();//设置响应的头信息,访问文件名中文乱码httpHeaders.setContentDispositionFormData("attachment", URLEncoder.encode(name,"utf-8"));ResponseEntity<byte[]> responseEntity = new ResponseEntity<>(buffer,httpHeaders, HttpStatus.OK);return responseEntity;}
- HttpServletResponse
@AutowiredHttpServletResponse response;@GetMapping("/test2")public void download2(String name) throws FileNotFoundException, UnsupportedEncodingException {//获取文件路径String realPath = request.getServletContext().getRealPath("/save/");//文件的全路径String allPath = realPath + name;//判断文件是否存在File file = new File(allPath);if (!file.exists()){throw new FileNotFoundException(name+"文件不存在");}//代码能执行到这一行,说明文件肯定存在//编码格式是utf-8的文件名String encodeFileName = URLEncoder.encode(name, StandardCharsets.UTF_8.toString());//设置头信息 headerresponse.setHeader("Content-Disposition","attachment;filename*=UTF-8''"+encodeFileName);//使用 try--with --resources 关闭流try(FileInputStream inputStream = new FileInputStream(file);OutputStream outputStream = response.getOutputStream()){IOUtils.copy(inputStream,outputStream);outputStream.flush();} catch (IOException e) {throw new RuntimeException(e);}}
异常处理
- 异常页面
-
- 修改web.xml (会直接跳到这个页面)
<error-page><location>/error.jsp</location></error-page>
- 异常类
@Component
public class TestController implements HandlerExceptionResolver {@Overridepublic ModelAndView resolveException(HttpServletRequest request,HttpServletResponse response,Object o,Exception e) {//产生异常的时候,调用这个方法System.out.println(e.getMessage());e.printStackTrace();//配置返回值ModelAndView mv = new ModelAndView();mv.setViewName("game/success");//会直接跳到 webapp下的这个页面return mv;}
}
- @RestControllerAdvice
用来处理指定异常(自定义异常类)
@RestControllerAdvice
public class JavasmExceptionAdvice {//当ArithmeticException被抛出来的时候,执行当前方法@ExceptionHandler(ArithmeticException.class)public String f1(ArithmeticException e){System.out.println("算术异常");e.printStackTrace();//返回值,会代替原有方法的返回内容return e.getMessage();}//当抛出JavasmException的时候,执行当前方法@ExceptionHandler(JavasmException.class)public Map<String,Object> f2(JavasmException e){Map<String,Object> map = new HashMap<>();map.put("code",500);map.put("msg","自定义异常"+e.getMessage());return map;}
}
public class JavasmException extends RuntimeException{public JavasmException() {}public JavasmException(String message) {super(message);}
}
拦截器
拦截器 和 过滤器 的区别是什么?
过滤器:web容器,不属于框架,请求进入tomcat之后,先经过的就是过滤器
拦截器:属于spring容器,springweb中,属于 容器的servlet,相当于,Servlet内部的请求拦截
public class TestInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {System.out.println("pre--xxx之前----在Controller的方法 执行之前");//返回的数据是Boolean类型,返回true,允许进入下一层(可能是下一个拦截器,也可能是Controller)//返回false????//response.getWriter().write("xxxx");return true;}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {System.out.println("post--xxx之后-----被访问的方法 执行结束之后,执行");}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {System.out.println("页面渲染成功之后执行");}
}
案例登录拦截public class LoginInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {//只有登录的用户才能访问系统HttpSession session = request.getSession();Object user = session.getAttribute("user");//登录的数据存在session,在这里取出if (user != null){//已经登录了return true;}Map<String,Object> map = new HashMap<>();map.put("code",2001);map.put("msg","未登录");String s = JSON.toJSONString(map);response.setContentType("application/json;charset=utf-8");//预防乱码PrintWriter writer = response.getWriter();writer.write(s);writer.flush();writer.close();return false;}
}
<?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"><!-- 开启包扫描--><context:component-scan base-package="com.javasm"/><!--代替适配器等配置--><mvc:annotation-driven/><!--视图解析器--><bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"><!--跳转的jsp页面,统一添加前缀--><property name="prefix" value="/WEB-INF/"/><!--后缀--><property name="suffix" value=".jsp"/></bean><!--静态资源文件放过--><mvc:default-servlet-handler/><!--上传文件的配置--><bean class="org.springframework.web.multipart.commons.CommonsMultipartResolver"><property name="defaultEncoding" value="utf-8"/></bean><!--配置拦截器--><mvc:interceptors><mvc:interceptor><!--被拦截的路径--><!--所有以/game开头的请求,都要经过拦截器--><mvc:mapping path="/game/**"/><mvc:mapping path="/player/**"/><!--在包含的路径中,排除其中的某些路径--><mvc:exclude-mapping path="/game/test1"/><!--拦截器类--><bean class="com.javasm.interceptor.TestInterceptor"/></mvc:interceptor><mvc:interceptor><mvc:mapping path="/**"/> //拦截页面的范围<mvc:exclude-mapping path="/game/test1"/> //不会被拦截的页面<mvc:exclude-mapping path="/login/**"/><bean class="com.javasm.interceptor.LoginInterceptor"/> //拦截所在的位置</mvc:interceptor></mvc:interceptors></beans>
数据类型转换
Field error in object 'bookModel' on field 'ctime': rejected value [2024-12-27]; codes [typeMismatch.bookModel.ctime,typeMismatch.ctime,typeMismatch.java.util.Date,typeMismatch]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [bookModel.ctime,ctime]; arguments []; default message [ctime]]; default message [Failed to convert property value of type 'java.lang.String' to required type 'java.util.Date' for property 'ctime'; nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type [java.util.Date] for value '2024-12-27'; nested exception is java.lang.IllegalArgumentException]]
表单提交的是String类型数据,尝试自动转成Date类型,失败了
@PostMapping("/doAdd2")@ResponseBodypublic Date doAdd2(String name,@DateTimeFormat(pattern = "yyyy-MM-dd") Date ctime){return ctime;}
@PostMapping("/doAdd")@ResponseBodypublic BookModel doAdd(BookModel book){return book;}@Data
public class BookModel {private Integer id;private String name;@DateTimeFormat(pattern = "yyyy-MM-dd")private Date ctime;
}
自定义参数类型转换器
SimpleDate转换
public class StringToDate implements Converter<String, Date> {@Overridepublic Date convert(String s) {//传入的参数,等待被转换的2024-12-27 字符串System.out.println(s);SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");Date date = null;try {date = simpleDateFormat.parse(s);} catch (ParseException e) {throw new RuntimeException(e);}return date;}
}
<?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"><!-- 开启包扫描--><context:component-scan base-package="com.javasm"/><!--代替适配器等配置--><mvc:annotation-driven conversion-service="conversionJavasmService"/><!--视图解析器--><bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"><!--跳转的jsp页面,统一添加前缀--><property name="prefix" value="/WEB-INF/"/><!--后缀--><property name="suffix" value=".jsp"/></bean><!--静态资源文件放过--><mvc:default-servlet-handler/><!--上传文件的配置--><bean class="org.springframework.web.multipart.commons.CommonsMultipartResolver"><property name="defaultEncoding" value="utf-8"/></bean><!--配置拦截器--><mvc:interceptors><mvc:interceptor><!--被拦截的路径--><!--所有以/game开头的请求,都要经过拦截器--><mvc:mapping path="/game/**"/><mvc:mapping path="/player/**"/><!--在包含的路径中,排除其中的某些路径--><mvc:exclude-mapping path="/game/test1"/><!--拦截器类--><bean class="com.javasm.interceptor.TestInterceptor"/></mvc:interceptor><mvc:interceptor><mvc:mapping path="/**"/><mvc:exclude-mapping path="/game/test1"/><mvc:exclude-mapping path="/login/**"/><bean class="com.javasm.interceptor.LoginInterceptor"/></mvc:interceptor></mvc:interceptors><!--消息类型转换--><bean id="conversionJavasmService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean"><property name="converters"><set><bean class="com.javasm.convert.StringToDate"/></set></property></bean></beans>
localdateTime
Field error in object 'bookModel' on field 'utime': rejected value [2024-12-27T16:08]; codes [typeMismatch.bookModel.utime,typeMismatch.utime,typeMismatch.java.time.LocalDateTime,typeMismatch]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [bookModel.utime,utime]; arguments []; default message [utime]]; default message [Failed to convert property value of type 'java.lang.String' to required type 'java.time.LocalDateTime' for property 'utime'; nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type [java.time.LocalDateTime] for value '2024-12-27T16:08'; nested exception is java.lang.IllegalArgumentException: Parse attempt failed for value [2024-12-27T16:08]]]
public class StringToDateTime implements Converter<String, LocalDateTime> {@Overridepublic LocalDateTime convert(String s) {return LocalDateTime.parse(s, DateTimeFormatter.ISO_LOCAL_DATE_TIME);}
}
<!--消息类型转换--><bean id="conversionJavasmService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean"><property name="converters"><set><bean class="com.javasm.convert.StringToDate"/><bean class="com.javasm.convert.StringToDateTime"/></set></property></bean>
JSON数据(用JSON传输数据)
- 引入依赖
<dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.11.2</version></dependency><dependency><groupId>com.fasterxml.jackson.datatype</groupId><artifactId>jackson-datatype-jsr310</artifactId><version>2.11.2</version></dependency>
- 加注解
@GetMapping ("/doAdd3")
@ResponseBody
public BookModel doAdd3(@RequestBody BookModel book){System.out.println(book);return book;
}
@Data
public class BookModel {private Integer id;private String name;//@DateTimeFormat(pattern = "yyyy-MM-dd")private Date ctime;@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")private LocalDateTime utime;
}
{"id":1001,"name":"<刑法>","ctime":"2024-12-27","utime":"2024-12-27 16:09:30"
}
json时间,可以写2024-01-27 09:09:09
不能写 2024-1-27 9:9:9