SpringMVC day02

SpringMVC day02

1 数据传输

从Controller跳转到View,通常是需要传输数据的。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rtdncbDp-1630975475698)(SpringMVC day02.assets/image-20210623224302104.png)]

1.1 请求转发中传递数据

1.1.1 Map、Model和ModelMap

SpringMVC中如果需要在一次请求中传递数据,可以使用Map、Model和ModelMap代替request作用域。

@RequestMapping("/data")
public class DataTransferController {
    @RequestMapping("/map")
    public String map(Map map){
        System.out.println("map = [" + map.getClass() + "]");
        map.put("map_name", "xiaohei");
        map.put("map_age", 18);
        map.put("map_u", new User(1, "xiaobai", "123456"));
        return "forward:/index.jsp";
    }

    @RequestMapping("/model")
    public String model(Model model) {
        System.out.println("model = [" + model.getClass()+ "]");
        model.addAttribute("model_name", "xiaohei");
        model.addAttribute("model_age", 18);
        model.addAttribute("model_u", new User(1, "xiaobai", "123456"));
        return "forward:/index.jsp";
    }

    @RequestMapping("/modelMap")
    public String modelMap(ModelMap map){
        System.out.println("modelMap = [" + map.getClass() + "]");
        map.put("modelMap_name", "xiaohei");
        map.put("modelMap_age", 18);
        map.addAttribute("modelMap_u", new User(1, "xiaobai", "123456"));
        return "forward:/index.jsp";
    }
}

index.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    map代替request作用域 <br>
    ${requestScope.map_name} <br>
    ${requestScope.map_age} <br>
    ${requestScope.map_u}
    <hr>
    model代替request作用域 <br>
    ${requestScope.model_name} <br>
    ${requestScope.model_age} <br>
    ${requestScope.model_u}
    <hr>
    modelMap代替request作用域 <br>
    ${requestScope.modelMap_name} <br>
    ${requestScope.modelMap_age} <br>
    ${requestScope.modelMap_u}
    <hr>
</body>
</html>

SpringMVC会自动为3种类型的参数注入对象,且都是同一类型的对象,3种方式本质上是同一种方式。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uae042Hd-1630975475701)(SpringMVC day02.assets/image-20210624194955183.png)]

1.1.2 ModelAndView[了解]

ModelAndView本身封装了一个ModelMap,它也可以用于传输数据。

@RequestMapping("/mav")
public ModelAndView modelAndView(){
    ModelAndView mav = new ModelAndView("forward:/index.jsp");
    mav.addObject("mav_name", "xiaohei");
    mav.addObject("mav_age", 18);
    mav.addObject("mav_-u", new User(1, "xiaobai", "123456"));
    return mav;
}
1.1.3 ModelAttribute注解[了解]

可以使用ModelAttribute注解描述方法形参,ModelAttribute描述的形参自动添加到Model中

@RequestMapping("modelAttribute")
public String modelAttribute(@ModelAttribute("name") String username,@ModelAttribute("age") Integer age,@ModelAttribute("u") User user){
    System.out.println("username = " + username + ", age = " + age + ", user = " + user);
    return "forward:/index.jsp";
}

index.jsp

modelAttribute代替request作用域 <br>
    ${requestScope.name} <br>
    ${requestScope.age} <br>
    ${requestScope.u} <br>

注意:

  • 请求中的简单类型参数名要和ModelAttribute保持一致
  • 数据保存在Model中以ModelAttribute注解值为数据名,而非形参名。上例中可以通过name 而不是 username从model中获取数据。

1.2 重定向中传递数据

1.2.1 Map、Model和ModelMap[了解]

Map、Model和ModelMap中保存的简单类型数据在重定向时会直接拼接在地址后

@RequestMapping("redirectPrimitive")
public String redirect(Map map, Model model, ModelMap modelMap) {
    map.put("name", "xiaohei");
    model.addAttribute("age", 18);
    //复杂类型数据无法拼接在地址栏
    modelMap.addAttribute("u", new User(1, "xiaohei", "123456"));

    return "redirect:/data/redirectValue.do";
}

地址栏地址变成:http://localhost:8989/springmvc-day02/data/redirectValue.do?name=xiaohei&age=18
    
@RequestMapping("redirectValue")
public String redirectValue(String name,Integer age,Model model){
    System.out.println("name = " + name + ", age = " + age);
    System.out.println("DataTransferController.redirectValue");
    model.asMap().forEach((k,v)->{
        System.out.println(k+" = " + v);
    });
    return "forward:/index.jsp";
}

注意:

  • 复杂数据不能拼接在地址栏,也就不能传递
  • 因为是直接拼接地址栏(明文显示),一般传递对安全性要求不高的数据
1.2.2 RedirectAttributes

RedirectAttributes也是Model的子类型,可以通过其独有的 addFlashAttribute 方法在重定向时传递复杂数据;传递的数据可以在重定向后的Controller服务方法的Model中获取

@RequestMapping("redirectObject")
public String redirectObject(RedirectAttributes model){
    System.out.println("model.getClass() = " + model.getClass());
    model.addFlashAttribute("redirect_name", "xiaohei");
    model.addFlashAttribute("redirect_age", 18);
    model.addFlashAttribute("redirect_u", new User(1, "xiaohei", "123456"));
    return "redirect:/data/redirectValue.do";
}

@RequestMapping("redirectValue")
public String redirectValue(String name,Integer age,Model model){
    System.out.println("name = " + name + ", age = " + age);
    System.out.println("DataTransferController.redirectValue");
    model.asMap().forEach((k,v)->{
        System.out.println(k+" = " + v);
    });
    return "forward:/index.jsp";
}

注意:

  • RedirectAttributes继承Model,继承到了addAttribute方法,使用时要和 addFlashAttributes 区分开来

  • RedirectAttributes底层使用session完成数据传递:

    1.重定向前将redirectAttributes中的数据保存到session

    2.重定向后从session中获取数据并保存到model中,然后从session中移除数据

1.3 Session作用域

1.3.1 HttpSession原生作用域

在SpringMVC中可以通过HttpSession对象操作session作用域。

@RequestMapping("session")
public String session(HttpSession session){
    session.setAttribute("session_name","xiaohei");
    session.setAttribute("session_age",18);
    session.setAttribute("session_u", new User(1, "xiaohei", "123456"));

    return "redirect:/index.jsp";
}

index.jsp

httpSession操作session作用域 <br>
${sessionScope.session_name} <br>
${sessionScope.session_age} <br>
${sessionScope.session_u}
<hr>
1.3.2 SessionAttributes注解[了解]

SessionAttributes注解用在类上面,将Model中的数据复制到Session作用域中。

//将Model中名为name和age,类型为User的数据复制到Session作用域
@SessionAttributes(value = {"name","age"},types = {User.class})
public class DataTransferController {
    ...
}

SessionAttributes添加到Session作用域的数据,在服务方法里可以直接从Model中获取到

@RequestMapping("getSessionAttributes1")
public String getSessionAttributes1(Model model){
    model.asMap().forEach((k,v)->{
        System.out.println(k+" = " + v);
    });
    return "redirect:/index.jsp";
}

SessionAttribute注解用在方法参数前,从Session作用域中获取数据赋值给参数。

@RequestMapping("getSessionAttributes2")
//SessionAttribute默认必须从session中获取到数据,获取不到抛异常;可以设置required=false不再要求必须获取到
public String getSessionAttributes2(@SessionAttribute(value = "name",required = false) String name,
                                    @SessionAttribute(value="age",required = false)Integer age,
                                    @SessionAttribute(value="u")User user){
    System.out.println("name = " + name + ", age = " + age + ", user = " + user);
    return "redirect:/index.jsp";
}

ModelAttribute注解也会从Session中获取SessionAttributes保存的数据,如果获取不到会抛异常。

@RequestMapping("getSessionAttributes3")
public String getSessionAttributes3(@ModelAttribute("name") String username,@ModelAttribute("age") Integer age,@ModelAttribute("u") User user){
    System.out.println("username = " + username + ", age = " + age + ", user = " + user);
    return "forward:/index.jsp";
}

注意:需要使用 SessionStatus清除SessionAttributes添加到session中的数据.

@RequestMapping("/clearSession")
public String clearSession(/*HttpSession session*/SessionStatus sessionStatus){
    //        session.removeAttribute("u");
    sessionStatus.setComplete();
    return "forward:/index.jsp";
}

2 ModelAttribute注解[了解]

ModelAttribute注解有2种用法:用在方法上和形参前。

2.1 用在方法上

ModelAttribute修饰的方法会自动的在每一个RequestMapping修饰的服务方法前执行。

  1. ModelAttribute修饰的方法可以定义和RequestMapping修饰方法相同的形参列表
  2. ModelAttribute修饰方法的返回值会自动添加到Model中(返回值类型也可以为void,则不做添加处理)
@Controller
@RequestMapping("/ma")
public class ModelAttributeController {
    
    @ModelAttribute("u")
    public User findUser(@RequestParam(value="id")Integer id, Model model){
        model.addAttribute("id",id);
        model.addAttribute("name", "xushy");

        User user = new User(1, "xiaohei", "123456");
        return user;
    }

    @RequestMapping("/method")
    public String testMethod(Map map){
        System.out.println(map.get("u"));//返回user对象
        System.out.println(map.get("name"));//"xushy"
        return "forward:/index.jsp";
    }
}

2.2 用在形参前

ModelAttribute注解用在形参前还可以从Model中获取数据,赋值给方法形参。

@Controller
@RequestMapping("/ma")
public class ModelAttributeController {
    @Autowired
    private UserService userService;

    @ModelAttribute("u")
    public User findUser(@RequestParam(value="id")Integer id, Model model){
        model.addAttribute("name", "xushy");
        User user = userService.showUser(id);
        return user;
    }

    @RequestMapping("/param")
    public String testParam(@ModelAttribute("u") User user,@ModelAttribute("age")Integer age){
        System.out.println("user = " + user + ", age = " + age);
        return "forward:/index.jsp";
    }
}

总结下ModelAttribute获取数据的方式以及先后顺序:

  1. 先从model中取同名数据
  2. 如果第1步获取不到,且SessionAttributes中保存了同名数据,则从session中获取,获取不到上抛异常
  3. 如果是简单类型参数,前2步获取数据则直接使用,未获取到则继续从请求中获取同名参数
    如果是复杂的对象类型参数,无论前2步是否获取到对象,在这一步都会从请求中获取参数为属性赋值

3 文件的上传和下载

3.1 文件复制

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zknDZAqx-1630975475702)(SpringMVC day02.assets/image-20210625091719397.png)]

上传和下载是通过网络完成的特殊的文件复制。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kQFgYLzC-1630975475704)(SpringMVC day02.assets/image-20210625091604584.png)]

Spring提供了文件复制的工具类:FileCopyUtils

@Test
public void testCopy2() throws IOException {
    InputStream in = new FileInputStream("D:/test.jpg");
	OutputStream out = new FileOutputStream("E:/test.jpg");
    FileCopyUtils.copy(in,out);
}

3.2 文件上传

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5fiALdYt-1630975475705)(SpringMVC day02.assets/image-20210625144851531.png)]

准备文件上传依赖:

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

页面:

<form action="${pageContext.request.contextPath}/file/upload.do" method="post" enctype="multipart/form-data">
    文件:<input type="file" name="pic" id=""> <br>
    文件描述: <textarea name="description" id="" cols="30" rows="10"></textarea><br>
    <input type="submit" value="提交">
</form>

Controller:

@RequestMapping("/file")
public class UploadController {
   @RequestMapping("upload")
    public String upload(MultipartFile pic, String description, HttpServletRequest request) throws IOException {
        System.out.println("pic = " + pic + ", description = " + description);
        //获取 项目中file文件夹的绝对路径
        String fileRealPath = request.getServletContext().getRealPath("/file/");
        System.out.println("fileRealPath = " + fileRealPath);

        //获取上传文件相关的输入流
        InputStream in = pic.getInputStream();
        //向file文件夹中输出文件
        OutputStream out = new FileOutputStream(fileRealPath + pic.getOriginalFilename());

        FileCopyUtils.copy(in,out);

        return "redirect:/index.jsp";
    }
}

springmvc-servlet.xml

<!-- 配置文件上传解析器
注意:这里的id必须固定,SpringMVC会根据此id找解析器。
-->
<bean class="org.springframework.web.multipart.commons.CommonsMultipartResolver" id="multipartResolver">
    <!-- 设置文件上传大小限制-->
    <property name="maxUploadSize" value="2097154"></property>
    <!-- 设置编码方式-->
    <property name="defaultEncoding" value="utf-8"/>
</bean>

3.3 文件下载

文件下载的思路:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-60x4Mo5e-1630975475706)(SpringMVC day02.assets/image-20210625145446594.png)]

页面:

<a href="${pageContext.request.contextPath }/file/download?fileName=test.txt">下载</a>

Controller:

@RequestMapping("/download")
public void download(String fileName, HttpServletRequest request,HttpServletResponse response) throws IOException {
    //1.通过文件名从file目录中获取文件相关的输出流
    String fileRealPath = request.getServletContext().getRealPath("/file/");
    InputStream in = new FileInputStream(fileRealPath+fileName);
    //2.设置响应格式和文件的名字
    response.setHeader("content-disposition","attachment;filename="+URLEncoder.encode(fileName,"utf-8"));
    //3.将文件通过resp的输出流,输出到client浏览器
    FileUtils.copyFile(in,response.getOutputStream());
}

新建一个项目,完成作业:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MZZFXpas-1630975475707)(SpringMVC day02.assets/image-20210302221116365.png)]

4 拦截器

SpringMVC的拦截器和Servlet中的Filter类似,可以在请求到达Controller之前先经过拦截器,在Controller处理完请求后,会再次反向经过拦截器。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lNIdHUgZ-1630975475708)(SpringMVC day02.assets/image-20210625150212547.png)]

作用:

  • 可以抽取Controller的共性代码,提高代码的复用性。
  • 拦截器可以改变请求的原始流程,可以用于强制登录。

4.1 第1个Interceptor程序

开发步骤:

  1. 编码

    public class LoginInterceptor implements HandlerInterceptor {
        @Override
        //请求到达Controller前执行,可用于登录校验
        public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
            //return true 放行请求  false 不放行
            HttpSession session = httpServletRequest.getSession();
            Object login = session.getAttribute("login");
            if(login != null){
                return true;
            }else {
                httpServletResponse.sendRedirect(httpServletRequest.getContextPath()+"/login.jsp");
                return false;
            }
        }
    
        @Override
        //Controller方法执行后,进入视图前:可修改视图的地址
        public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
    
        }
    
        @Override
        //最后执行,可用于释放资源,或者异常的记录
        public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
    
        }
    }
    
  2. 配置

    <mvc:interceptors>
        <mvc:interceptor>
            <mvc:mapping path="/**"/>
            <mvc:exclude-mapping path="/login.do"/>
            <mvc:exclude-mapping path="/register.do"/>
            <bean class="com.baizhi.interceptor.LoginInterceptor"/>
        </mvc:interceptor>
    </mvc:interceptors>
    

4.2 多个Interceptor的执行流程

(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {

   }

}




2. 配置

```xml
<mvc:interceptors>
    <mvc:interceptor>
        <mvc:mapping path="/**"/>
        <mvc:exclude-mapping path="/login.do"/>
        <mvc:exclude-mapping path="/register.do"/>
        <bean class="com.baizhi.interceptor.LoginInterceptor"/>
    </mvc:interceptor>
</mvc:interceptors>

4.2 多个Interceptor的执行流程

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cBanr1Am-1630975475709)(SpringMVC day02.assets/55ab23425a904dfe9ff076c60a171e1e~tplv-k3u1fbpfcp-watermark.image)]

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
SpringMVC 中,我们可以通过 ResponseBody 注解返回音频流,具体步骤如下: 1. 在 Controller 中定义一个返回类型为 ResponseEntity<byte[]> 的方法,该方法需要使用 @ResponseBody 注解标注。 2. 在方法中获取音频文件的字节数组,并将其放入 ResponseEntity 对象中返回。 3. 在 ResponseEntity 对象中设置 Content-Type、Content-Disposition 等响应头,以便浏览器正确解析音频流并进行播放。 示例代码如下: ```java @RequestMapping("/audio") @ResponseBody public ResponseEntity<byte[]> getAudio() throws IOException { // 读取音频文件字节数组 InputStream in = getClass().getResourceAsStream("/static/audio/sample.mp3"); byte[] audioBytes = IOUtils.toByteArray(in); // 设置响应头 HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.parseMediaType("audio/mpeg")); headers.setContentDispositionFormData("attachment", "sample.mp3"); // 返回音频流 return new ResponseEntity<>(audioBytes, headers, HttpStatus.OK); } ``` 上述代码中,我们将音频文件 sample.mp3 放在了项目的 /static/audio 目录下。在方法中,我们使用 IOUtils.toByteArray() 方法将音频文件转换为字节数组,并将其放入 ResponseEntity 对象中返回。在设置响应头时,我们使用 MediaType.parseMediaType() 方法设置 Content-Type,使用 setContentDispositionFormData() 方法设置 Content-Disposition。最后,我们通过 new ResponseEntity<>(audioBytes, headers, HttpStatus.OK) 创建 ResponseEntity 对象并返回。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值