springMVC第二天笔记

SpringMVC第二天

一、内容介绍

1、ModelAttribute和SessionAttribute注解的使用

2、RestFul风格

3、控制器方法的返回值

4、交互JSON数据

5、springMVC实现文件上传

6、springMVC异常处理

二、ModelAttribute和SessionAttribute注解的使用

@ModelAttribute标记在方法上
当表单提交数据不是完整的实体类数据时,保证没有提交数据的字段使用数据库对象原来的数据。

  1. 特点:当执行控制器中任何一个方法时,都会先执行@ModelAttribute标记的方法
  2. 缺点:慎重使用,因为执行控制器中任何一个方法时,都会先执行@ModelAttribute标记的方法, 效率太低
用法一:有返回值
 	@ModelAttribute
    public User findById(Integer id){
        User user = new User();
        user.setUsername("王五");
        user.setSex("女");
        return user;
    }

    /**
     * update user set username = ? ,sex = ? where id = ?
     * @ModelAttribute:在执行控制器中任何一个方法时,都会先执行
     *   findById方法返回一个User对象
     *   判断参数user中的属性是否为null,如果为null,则使用findById的方法返回值中的数据覆盖
     */
    @RequestMapping(value = "/testUpdate",method = RequestMethod.POST)
    public String testUpdate(User user){
        System.out.println(user);
        System.out.println("更新");
        return "show";
    }
    
用法二:没有返回值
 @ModelAttribute
    public void findById(Integer id, Map<String ,Object> map){
        User user = new User();
        user.setUsername("王五");
        user.setSex("女");

        map.put("aa",user);
    }

    @RequestMapping(value = "/testUpdate",method = RequestMethod.POST)
    public String testUpdate(@ModelAttribute("aa") User user){
        System.out.println(user);
        System.out.println("更新");
        return "show";
    }
 

注解@SessionAttributes:在session范围内存储对象

	1) @SessionAttributes({"username","password"}) 在类上标记该注解
		在session范围可以存储这两个变量名
	2) /**
     * 把用户名和密码存入到Session范围内
     */
    @RequestMapping("/testPut")
    public void testPut(Model model){
        model.addAttribute("username","zhangsan");
        model.addAttribute("password","123456");
    }

   3)  /**
     * 获取session范围内的对象
     */
    @RequestMapping("/testGet")
    public void testGet(ModelMap modelMap){
        Object username = modelMap.get("username");
        System.out.println(username);
        Object password = modelMap.get("password");
        System.out.println(password);
    }

    4) /**
     * 清空session
     * @param sessionStatus
     */
    @RequestMapping("/testClear")
    public void testClear(SessionStatus sessionStatus){ 
   	 	sessionStatus.setComplete();
    }

三、RestFul风格

a. rest 是一种编程风格
b. 满足了rest风格的网站就是restful风格
c. 只是一种规范,不是规则

根据id获取一个用户:/user/findById?id=1	restful风格:/user/operate/1 使用get方式提交
根据id删除一个用户:/user/delById?id=1	restful风格:/user/operate/1 使用delete方式提交
更新一个用户:/user/update?id=1&name=z 	restful风格:/user/operate/1 使用put方式提交
添加一个用户:/user/save?id=1&name=z      restful风格:/user/operate 使用post方式提交

d、优势:传统的请求意图明显,造成数据不安全,restful风格提高数据的安全性

根据id获取
	页面
		http://localhost:8080/user/operate/1
	方法
	/**
     * 根据id查询
     */
    @RequestMapping(value = "/operate/{id}",method = RequestMethod.GET)
    public String findById(@PathVariable("id") Integer id){
        System.out.println("findById:"+id);
        return "show";
    }
    
添加一个用户
	页面
	 <%--请求保存用户--%>
    <form action="${pageContext.request.contextPath}/user/operate/1" method="post">
        <input type="submit" value="提交">
    </form>
    
	方法
	/**
     * 保存用户
     */
    @RequestMapping(value = "/operate/{id}" , method = RequestMethod.POST)
    public String save(@PathVariable("id") Integer id){
        System.out.println("save:" + id);
        return "show";
    }
    
更新用户
 	页面:
 	<%--请求更新用户--%>
    <form action="${pageContext.request.contextPath}/user/operate/1" method="post">
        <%--要使用put,delete提交方式
                 1) 在web.xml开启put和delete提交方式
                 2) 表单的提交方式必须post
                 3) 表单中必须设置一个隐藏域 name=_method value=PUT
                 4) 请求的方法返回值必须以流的形式返回,在方法上标记注解:@ResponseBody
                       流的形式返回: response.getWriter().print()
                       因为页面中只有GET和POST,无法接收其他两种方式的返回值
                --%>
        <input type="hidden" name="_method" value="PUT">
        <input type="submit" value="更新">
    </form>
    
    方法
     /**
     * 更新用户
     */
    @RequestMapping(value = "/operate/{id}" , method = RequestMethod.PUT)
    @ResponseBody
    public String update(@PathVariable("id") Integer id){
        System.out.println("update:" + id);
        return "show";
    }
 i. 删除用户
 	页面
 	<%--请求删除用户--%>
    <form action="${pageContext.request.contextPath}/user/operate/1" method="post">
        <input type="hidden" name="_method" value="DELETE">
        <input type="submit" value="删除">
    </form>
    
    方法
     /**
     * 删除用户
     */
    @RequestMapping(value = "/operate/{id}" , method = RequestMethod.DELETE)
    @ResponseBody
    public String delById(@PathVariable("id") Integer id){
        System.out.println("delById:" + id);
        return "show";
    }

web.xml

	<!--开启另外两种提交方式:put, delete-->
  <filter>
    <filter-name>HiddenHttpMethodFilter</filter-name>
    <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>HiddenHttpMethodFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>

四、控制器方法的返回值

1、返回值为void类型
a. 方法一:
	@RequestMapping("/testVoid")
   public void testVoid(){
        System.out.println("测试没有返回值");
        //因为没有指定返回值页面,会自动截取请求路径,进入视图解析器,拼接完整的路径
        //可以对应的路径下创建对应的jsp页面
   }
b. 方法二:response重定向
@RequestMapping("/testVoid2")
    public void testVoid2(HttpServletResponse response){
        System.out.println("测试没有返回值");
        try {
            //重定向不能进入web-inf路径
            //转发可以进入web-inf路径
            response.sendRedirect("/index.jsp");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
c. 方法三:转发
	@RequestMapping("/testVoid3")
    public void testVoid3(HttpServletResponse response, HttpServletRequest request){
        System.out.println("测试没有返回值");
        try {
            request.getRequestDispatcher("/WEB-INF/show.jsp").forward(request,response);
        } catch (Exception e) {
            e.printStackTrace();
        } 
    }
2、返回值为String类型(常用)
a. 默认的情况:请求转发,返回值直接进入视图解析器,拼接前缀和后缀得到完整的路径
	/**
     * 方法的返回值为String类型
     */
    @RequestMapping("/testReturnString")
    public String testReturnString(){
        return "show";
    }
    
 b. 请求重定向
 	/**
     * 执行保存操作-- 重新查询 : save -- redirect:findAll
     *   
     *   redirect:添加了redirect后则不会进入视图解析器,需要配置完整的路径
     *   redirect:重定向, 不能进入web-inf
     */
    @RequestMapping("/testReturnString2")
    public String testReturnString2(){
        return "redirect:/index.jsp";
    }
    
 c. 请求转发
 	/**
     * forward: 转发,不会进入视图解析器,需要配置完整的路径
     */
    @RequestMapping("/testReturnString3")
    public String testReturnString3(){
        return "forward:/index.jsp";
    }
3、返回值为ModelAndView类型(常用)

Model 模型:封装数据 view 视图: 指定页面 —> 模型和视图

扫描二维码关注公众号,回复: 9401612 查看本文章
 /**
     * 返回值类型为ModelAndView,包含数据和视图页面
     * @return
     */
    @RequestMapping("/testReturnModelAndView")
    public ModelAndView testReturnModelAndView(){
        //准备数据--数据库查询
        List<User> userList = new ArrayList<>();
        User user = new User();
        user.setUsername("zhangsan");
        user.setSex("男");
        user.setId(2);

        User user1 = new User();
        user1.setUsername("zhangsan1");
        user1.setSex("女");
        user1.setId(1);

        userList.add(user);
        userList.add(user1);
        ModelAndView modelAndView = new ModelAndView();
        //添加数据
        	//modelAndView以键值对形式存放数据
        modelAndView.addObject("userList",userList);
        //指定页面
        	//页面中可以用el获取数据:${键名}
        modelAndView.setViewName("show");
        return  modelAndView;
    }

五、交互JSON数据

  1. 引入依赖
<!--引入json的依赖-->
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-core</artifactId>
      <version>2.9.0</version>
    </dependency>
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-databind</artifactId>
      <version>2.9.0</version>
    </dependency>
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-annotations</artifactId>
      <version>2.9.0</version>
    </dependency>

ReqeustBody注解(不适用于GET提交)

controller:
 	@RequestMapping("/testRequestJson")	//参数名与键名一致也可获得数据
    public void testRequestJson(String username ,Integer age){
        System.out.println(username);
        System.out.println(age);
    }

    /**
     * @RequestBody: 可以把所有参数转换为字符串
     * @param body
     */
    @RequestMapping("/testRequestJson2")
    public void testRequestJson2(@RequestBody  String body){
        System.out.println(body);
    }
    	结果:username=zhangsan&age=20
	页面:
		$.ajax({
            url:"${pageContext.request.contextPath}/user/testRequestJson2",
            data:{"username":"zhangsan","age":20},
            type:"post",
            dataType:"json",
            success:function(data){
               
            }
    });

ResponseBody注解
该注解用于将 Controller 的方法返回的对象,通过 HttpMessageConverter 接口转换为指定格式的数据如:json等,通过 Response 响应给客户端

controller:
	/**
     * @ResponseBody :标记了@ResponseBody注解的方法,数据会以流的方式返回
     */
    @RequestMapping("/testResponseBody")
    @ResponseBody
    public List<User> testResponseBody(){
        List<User> userList = new ArrayList<>();
        User user = new User();
        user.setUsername("zhangsan");
        user.setSex("男");
        user.setId(2);

        User user1 = new User();
        user1.setUsername("zhangsan1");
        user1.setSex("女");
        user1.setId(1);

        userList.add(user);
        userList.add(user1);

        return userList;
    }
    
    页面:
      $.ajax({
            url:"${pageContext.request.contextPath}/user/testResponseBody",
            data:{},
            type:"post",
            dataType:"json",
            success:function(data){
                alert(data[0].username);
                alert(data[1].username);
            }
        });

引入静态资源后,必须静态资源放行

	<!--对静态资源放行
        把js下的静态资源映射到js目录下
    -->
    <mvc:resources mapping="/js/*" location="/js/"></mvc:resources>

六、SpringMVC实现文件上传

1、文件上传

a、引入依赖
引入fileUpload会自动依赖commons-io
	<dependency>
      <groupId>commons-fileupload</groupId>
      <artifactId>commons-fileupload</artifactId>
      <version>1.3.1</version>
    </dependency>
b、spring-mvc.xml 配置文件
		<!-- 配置文件上传解析器 -->
    <!-- id的值是固定的-->
    <bean id="multipartResolver"
          class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <!-- 设置上传文件的最大尺寸为5MB -->
        <property name="maxUploadSize">
            <value>5242880</value>
        </property>
    </bean>
c、页面配置
<%--
      上传文件的表单前提:
            1) 提交方式必须是post
            2) 表单的类型必须:multipart/form-data, 多功能表单数据
            3) 必须有一个type=file的表单元素
    --%>
    <form action="${pageContext.request.contextPath}/user/upload" method="post" enctype="multipart/form-data">
        <input type="text" name="username"> <br>
        <input type="file" name="upload"><br>
        <input type="submit" value="上传">
    </form>
d、controller代码
	/**
     * 声明参数 变量接收数据
     */
    @RequestMapping("/upload")
    public String upload(String username , MultipartFile upload, HttpServletRequest request){
    
        //1. 目标路径
        //获取项目运行的路径
        String realPath = request.getSession().getServletContext().getRealPath("/upload");
        //判断该路径是否存在
        File realFile = new File(realPath);
        if(!realFile.exists()){
            realFile.mkdirs();
        }
        
        //2. 获取唯一的文件名称(包含扩展名)
        String uuidName = UUID.randomUUID().toString().replace("-", "");
        //获取扩展名: 获取文件名
        //获取真实的文件名
        String originalFilename = upload.getOriginalFilename();
        //截取字符串,获取文件的扩展名
        String extendName = originalFilename.substring(originalFilename.lastIndexOf("."));
        System.out.println(extendName);
        //唯一的文件名
        String fileName = uuidName + extendName;
        System.out.println(fileName);

        //3.文件上传
        //transferTo: 执行文件上传
        //参数file:目录文件
        try {
            upload.transferTo(new File(realFile, fileName));
        } catch (IOException e) {
            e.printStackTrace();
        }
        return "show";
    }

2、跨服上传

a、引入依赖
<!--引入jersey服务器的包-->
    <dependency>
      <groupId>com.sun.jersey</groupId>
      <artifactId>jersey-core</artifactId>
      <version>1.18.1</version>
    </dependency>
    <dependency>
      <groupId>com.sun.jersey</groupId>
      <artifactId>jersey-client</artifactId>
      <version>1.18.1</version>
    </dependency>
b、修改tomcat配置
1. tomcat默认不能跨服上传的
2. tomcat/conf/web.xml 	
		<init-param>
            <param-name>debug</param-name>
            <param-value>0</param-value>
        </init-param>
    <!--需要添加的-->
		<init-param>
    	<param-name>readonly</param-name>
    	<param-value>false</param-value>
    </init-param>
c、配置图片服务器
  1. 创建一个web项目
  2. 配置一个tomcat,与原来tomcat端口号不一致
  3. 在webapp目录下创建一个upload目录,空的文件夹不会编译,需要在upload目录添加(任意)一个文件
d、修改controller代码
	/**
     * 声明参数 变量接收数据
     */
    @RequestMapping("/uploadServer")
    public String uploadServer(String username , MultipartFile upload, HttpServletRequest request){
    
        //1. 配置图片服务器的路径
        String serverPath = "http://localhost:9090/img_server/upload/";
        
        //2. 获取唯一的文件名称(包含扩展名)
        String uuidName = UUID.randomUUID().toString().replace("-", "");
        String originalFilename = upload.getOriginalFilename();
        String extendName = originalFilename.substring(originalFilename.lastIndexOf("."));
        String fileName = uuidName + extendName;
        System.out.println(fileName);

        //3.获取jersey服务器客户端
        Client client = Client.create();
        //配置上传路径的资源对象
        WebResource resource = client.resource(serverPath + fileName);
        //上传
            //参数:资源的类型
            //文件的字节内容
        try {
            resource.put(String.class,upload.getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        }
        return "show";
  }

七、SpringMVC的统一异常处理

  1. 自定义异常类
public class CustomException extends  Exception {

    private String message;

    public CustomException(String message) {
        super(message);
        this.message = message;
    }

    @Override
    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}

  1. 定义异常的统一处理器——实现接口:HandlerExceptionResolver
/**
 * 自定义的异常统一处理对象
 * 
 */
@Component
public class MyExceptionResolver implements HandlerExceptionResolver {

    /**
     * 解析异常
     * @param request
     * @param response
     * @param handler
     * @param e 其他模块传过来的异常对象
     * @return
     */
    @Override
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception e) {
        ModelAndView modelAndView = new ModelAndView();
        //添加数据
        //instanceof: 实例类型判断运算符
        if(e instanceof CustomException){
            //强制转换
            CustomException customException = (CustomException) e;
            modelAndView.addObject("message",customException.getMessage() );
        }else{
            modelAndView.addObject("message","系统错误,请联系管理员!!!");
        }
        //指定页面
        modelAndView.setViewName("error");
        return modelAndView;
    }
}

  1. 错误页面
<%@ page isELIgnored="false" contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    ${message}
</body>
</html>
发布了33 篇原创文章 · 获赞 2 · 访问量 974

猜你喜欢

转载自blog.csdn.net/Rhin0cer0s/article/details/100062106