Spring-mvc(day2)

123 阅读6分钟

一、JSON(了解)

这里主要掌握将后台向前台传递的数据转换为JSON格式,对JSON只是了解,后面会详细介绍JSON

1、JSON概述

JSON是轻量级的数据格式,通常需要和别的系统 交换数据,交换数据的格式通常有XML和JSON(现在XML基本只用来做配置文件,不再用来传输数据),基于JavaScript语法的轻量级数据交换格式,使用JavaScript语法来描述数据对象

2、JSON语法

2.1、表示一个对象

因为JSON是一种弱类型语言,没有基本数据类型(java里的int、long等),所以所有类型都用var表示

var user = {
    "id":1,
    "name":"张三",
    "age":23,
    "dep":{
        "dep_id":1,
        "dep_name":"综合部",
    }
}

2.2、表示一个数组

var obj = []
var dept={
    "id":1,
    "emps":[
        {
            "id":1,
            "name":"a",
        },
        {
            "id":2,
            "name":"b",
        }
    ]
}

2.3、JSON字符串

使用方法JSON.stringify(对象),如将上面的dept转换为字符串

JSON.stringify(dept)

image.png

二、SpringMVC返回JSON

1、准备工作

有时候需要向前台传递JSON格式的数据,需要将java对象转换为JSON,而Spring框架是不支持转换格式的,就需要第三方的支持(如果导入Jackson的依赖会出现406异常),我们这里导入Jackson的依赖

<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-databind</artifactId>
  <version>2.9.10.8</version>
</dependency>

2、常用注解

  • @RequestBody

方式一:返回字符串加上此注解就会把返回值当作响应内容,且不会经过视图解析器,不会返回字符串内容的页面,就可以在括号里写JSON的内容

@RequestMapping("/test01")
@ResponseBody
public String test01(){
    return "hello.json";
}

image.png 方式二:以JSON格式在页面展示User对象

创建User对象和COntroller类

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private Long id;
    private String name;
    private Integer age;
    private Date birthday;
}
@RequestMapping("/test02")
@ResponseBody
public User test02(){
    return new User(1l,"zs",18,new Date());
}

image.png

  • @JsonFormat

主要对后台传向前台的日期格式进行处理,上面JSON显示的日期格式为时间戳,而在前台希望我们指定规则的日期字符串,也就是平常看到的时间(xx年x月x日),这里我们就需要引用此注解,只需要在日期的属性上方添加注解就好

@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
private Date birthday;

image.png

  • @DateTimeFormat

前台给后台传日期也需要进行转换,和上面一样在日期属性上打上注解,前台给后台传输数据就不用设置时区

@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
@DateTimeFormat(pattern ="yyyy-MM-dd HH:mm:ss" )
private Date birthday;

三、文件上传与下载

文件上传

1、准备工作

添加依赖:SpringMVC自己没有实现文件上传

 <dependency>
      <groupId>commons-fileupload</groupId>
      <artifactId>commons-fileupload</artifactId>
      <version>1.3.3</version>
    </dependency>
<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.4</version>
</dependency>

配置上传解析器

<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    <!-- 设置上传文件的最大尺寸为10MB,1024*1024=10485760 -->
    <property name="maxUploadSize" value="10485760" />
</bean>

2、jsp页面

  • 表单提交方式必须是post请求(get请求是uri拼接,只能传2k,不适合传输文件)
  • 表单中必须有文件上传项<input type="file" name="headImg">,name值自定义
  • 表单需要有enctype属性,属性值必须是multpart/form-data
<form action="/upload" method="post" enctype="multipart/form-data">
    头像:<input type="file" name="headImg">
<input type="submit" value="上传">
</form>

3、后台处理

表单传的是复杂表单数据,需要使用复杂文件MultipartFile接收。这里主要解决两个问题,第一是文件名不能相同,不然后上传的文件会覆盖之前上传的同名文件;第二是上传的路径不能写绝对路径,不然只能在本机上跑,换一台设备路径不对就不能正常使用,如下

String filename=fileUpload.getOriginalFilename();
//接收用户上传的输入流
InputStream is = fileUpload.getInputStream();
//将文件输出到指定路径
FileOutputStream os = new FileOutputStream("D:\JavaWorks\space\springmvc_day2\src\main\webapp\imgs\" + filename);
IOUtils.copy(is,os);
os.close();
is.close();
//上传成功后跳转的页面
return "/success.jsp";

解决方法:在文件上传过程中在前面加一串随机数作为前缀就可解决文件重名覆盖问题;使用Request获取真实路径可以避免绝对路径,具体操作如下

//入参用headImg  或者使用注解@RequestParam("headImg")
@Controller
public class UploadController {
    @RequestMapping("/upload")
    public String upload(@RequestParam("headImg") MultipartFile fileUpload , HttpServletRequest request) throws Exception{//用headImg  或者使用注解@RequestParam("headImg")
  
        //获取上传文件名
        String filename = fileUpload.getOriginalFilename();
        //使用随机数给文件名添加前缀
        String profix = UUID.randomUUID().toString().replaceAll("-", "");
        String name=profix+filename;

        //动态获取磁盘路径
        String realPath = request.getServletContext().getRealPath("imgs");
        //如果没有imgs文件夹,就创建一个再输出
        File file = new File(realPath);
        if (!file.exists()){
            file.mkdir();
        }
        //接收用户上传的输入流
        InputStream is = fileUpload.getInputStream();
        //将文件输出到路径
        FileOutputStream os = new FileOutputStream(realPath + "/" + name);


        IOUtils.copy(is,os);
        os.close();
        is.close();
        //上传成功后跳转的页面
        return "/success.jsp";
    }
}

文件下载

1、前台代码

前台使用超链接跳转到后台控制台,在控制台通过流的方式进行操作,如下将拿到1.jpg的图片

image.png

2、后台代码

以流的形式响应页面,不需要返回值,需要判断文件是否存在,存在才能输出;并且要设置文件下载的名字(response.setHeader("Content-Disposition", "attachment; filename=" +文件下载的名字)),不然只会预览,而不是下载

@RequestMapping("/download")
public void download(String name, HttpServletRequest request, HttpServletResponse response) throws Exception {
    String realPath = request.getServletContext().getRealPath("imgs");
    File file = new File(realPath, name);
    //exists 判断文件是否存在  存在为true  不存在为false
    if (file.exists()){
        //文件存在  读取文件
        FileInputStream fis = new FileInputStream(file);

        //告诉浏览器这是一个包含附件的响应  就会进行下载处理  否则只是预览
        response.setHeader("Content-Disposition", "attachment; filename=" + name);
        //2.2.获取输出流
        //获取输出流   从响应中拿
        ServletOutputStream os = response.getOutputStream();
        IOUtils.copy(fis,os);
        os.close();
        fis.close();
    }
}

四、SpringMVC拦截器

配置拦截器(在xml配置文件里) 需要实现HandlerInterceptor接口,主要使用的preHandle()方法,可以通过它来判断用户登录(之后使用)

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    System.out.println("到达前置拦截");
    //这里可以判断用户是否登录 
    //没有登录可以使用 request/response跳转回登录页面
    //注:如果不继续执行返回false,否则返回true
    return true;
}

五、SpringMVC执行流程

image.png

1、用户发起请求提交到DispatcherServlet(加载SpringMVC.xml文件,根据配置文件查找才能决定请求需要往哪儿发送)

2、DispatcherServlet将请求交给HandlerMapping进行请求映射(dispatcherServlet通过映射找到对应的COntroller)

3、HandlerAdapter识别COntroller是拿哪种方式实现的

4、到整个业务流程:COntroller层 -> service层 -> dao层

5、所有业务处理完以后,COntroller会返回一个modelAndView(是空页面,还不能返回给用户)到DispatcherServlet

6、根据返回的DispatcherServlet找合适的ViewResolver(视图解析器,找页面),然后将数据和页面进行结合,形成有数据的完整页面响应给页面