当前位置: 首页 > article >正文

24.12.27 SpringMVCDay02

    • 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>
    @Autowired
    HttpServletRequest request;

    @PostMapping("/doUpload1")
    @ResponseBody
    public 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")
    @ResponseBody
    public 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")
    @ResponseBody
    public 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")
    @ResponseBody
    public 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
    @Autowired
    HttpServletRequest 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
    @Autowired
    HttpServletResponse 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());
        //设置头信息 header
        response.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 {
    @Override
    public 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 {

    @Override
    public 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;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("post--xxx之后-----被访问的方法 执行结束之后,执行");

    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("页面渲染成功之后执行");
    }
}
案例登录拦截

public class LoginInterceptor implements HandlerInterceptor {

    @Override
    public 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/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
         https://www.springframework.org/schema/context/spring-context.xsd
         http://www.springframework.org/schema/mvc
         https://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")
    @ResponseBody
    public Date doAdd2(String name,@DateTimeFormat(pattern = "yyyy-MM-dd") Date ctime){
        return ctime;
    }
    @PostMapping("/doAdd")
    @ResponseBody
    public 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> {
    @Override
    public 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/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
         https://www.springframework.org/schema/context/spring-context.xsd
         http://www.springframework.org/schema/mvc
         https://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> {
    @Override
    public 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


http://www.kler.cn/a/459443.html

相关文章:

  • 【微信小程序获取用户手机号
  • 《米塔》为什么能突破160万销量?
  • 每天你好20250105(距离春节24天!!!)
  • java中static和const和final的区别
  • 高等数学学习笔记 ☞ 无穷小比较与等价无穷小替换
  • 【文献精读笔记】Explainability for Large Language Models: A Survey (大语言模型的可解释性综述)(三)
  • python3中条件判断语句:if 语句与if嵌套语句
  • CSS利用浮动实现文字环绕右下角,展开/收起效果
  • 从论文到实践:Stable Diffusion模型一键生成高质量AI绘画
  • 【笔记️】魔爪 Mini mx 使用快捷键
  • 深入解析C#异步编程:await 关键字背后的实现原理
  • Vue.js 生命周期概述:组件从诞生到销毁的全过程
  • Python世界:函数模块知识点小结
  • pytorch torch.utils.checkpoint模块介绍
  • Golang协程为什么⽐线程轻量
  • o1到o3的发展历程
  • lombok-macros
  • 【Go】context标准库
  • 步进电机驱动算法——S形加减速算法原理
  • 面试经典150题——数组/字符串(二)
  • 开发运维基本功:无需复杂配置快速实现本地Nginx的公网远程访问
  • 【文献精读笔记】Explainability for Large Language Models: A Survey (大语言模型的可解释性综述)(三)
  • 打破传统,手势验证码识别
  • DP协议:PHY层
  • JS - Array Api
  • 从零开始学架构——互联网架构的演进