学习笔记_SpringMVC_02

通过处理器方法返回值指定返回视图

SpringMVC中的处理器方法的返回值用来指定页面跳转到哪个视图,处理器的返回值可以为String,void,ModelAndView对象.
处理器返回String对象: 转发到字符串指定的URL
处理器方法返回字符串可以指定逻辑视图名,通过视图解析器解析为物理视图地址.

@Controller
@RequestMapping("/user")
public class UserController {
    //返回值类型是String
    @RequestMapping("/testString")
    public String testString(Model model){
        System.out.println("testString执行了");
        //模拟从数据库查询出的User对象
        User user = new User();
        user.setUsername("meimei");
        user.setAge(23);
        user.setPassword("123");
        //model对象存储数据
        model.addAttribute("user",user);
        return "success";
    }

处理器返回void: 转发到当前URL
若处理器返回void,表示执行完处理器方法体内代码后,不进行请求转发,而直接转发到当前URL.若没有在web.xml中配置当前对应的url-pattern,则会返回404错误.

//返回值类型是void
    @RequestMapping("/testVoid")
    public void testVoid(Model model){
        System.out.println("testVoid执行了");
    }

处理器返回ModelAndView对象: 更灵活地添加属性和指定返回视图
ModelAndView为我们提供了一种更灵活地为页面添加属性和指定返回视图的方法,其主要方法如下:

public ModelMap getModelMap(): 返回当前页面的ModelMap对象.
public ModelAndView addObject(Object attributeValue): 向当前页面的ModelMap对象中添加属性
public void setViewName(@Nullable String viewName): 指定返回视图,viewName会先被视图解析器处理解析成对应视图.

 //返回值类型是ModelAndView
    @RequestMapping("/testModelAndView")
    public ModelAndView testModelAndView(Model model){

        ModelAndView mv = new ModelAndView();
        System.out.println("testModelAndView");
        //模拟从数据库查询出的User对象
        User user = new User();
        user.setUsername("meimei");
        user.setAge(23);
        user.setPassword("123");

        //把user对象存储到mv对象中,也会把user对象存入到request对象
        mv.addObject("user",user);

        //跳转到哪个页面
        mv.setViewName("success");

        return mv;

SpringMVC响应json数据

准备

1.要将json字符串与JavaBean对象相互转换,我们需要引用jackson的jar包,在pom.xml中添加依赖坐标如下:

<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-core</artifactId>
    <version>2.9.0</version>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-annotations</artifactId>
    <version>2.9.0</version>
</dependency

2.jsp在页面上引入jQuery以发送json数据,因此需要向服务器发起一个对jQuery的请求.像这种对静态资源的请求,不应当经过具体的某个处理器处理,而应当直接返回对应的静态资源.
因此我们需要在Spring容器配置bean.xml中使用<mvc:resources>标签声明该资源为静态资源,否则请求该资源会报404错误.该标签的属性如下:
location属性: 表示该资源在服务器上所在的位置,必须是一个有效的目录
mapping属性: 指定匹配的URL

我们在springmvc.xml中配置各静态文件的位置如下:

   <!--前端控制器,哪些静态资源不拦截-->
   <!-- location属性必须是一个有效的目录,因此必须以 / 结尾 -->
    <mvc:resources location="/css/" mapping="/css/**"/>
    <mvc:resources location="/images/" mapping="/images/**"/>
    <mvc:resources location="/js/" mapping="/js/**"/>

发送json数据

在jsp页面中编写代码发送json请求如下:

// 页面加载,绑定单击事件
        $(function () {
            $("#btn").click(function () {
                //alert("hello")
                //发送Ajax请求
                $.ajax({
                    //json格式.设置属性和值
                    url:"user/testAjax",
                    contentType:"application/json;charset=UTF-8",
                    data:'{"username":"hehe","password":"123","age":30}',
                    dataType:"json",
                    type:"post",
                    success:function (data) {
                        //data指服务器端响应的json数据,进行解析
                        alert(data);
                        alert(data.username);
                        alert(data.age);
                        alert(data.password) }
                })
            })
        })

在控制器中编写代码响应json数据
使用@RequestBody注解将请求体绑定到控制器方法参数上,使用@ResponseBody注解表示将该方法的返回值直接写回到HTTP响应中,而不是存入Model或解析为视图名.
jackson包自动完成从Java实体类到json数据之间的相互转换.

  //模拟异步请求响应
    @RequestMapping("/testAjax")
    public @ResponseBody User testAjax(@RequestBody User user){
        System.out.println("testAjax");
        System.out.println(user);
        //做响应
        user.setUsername("aas");
        user.setAge(54);
        return user;
    }

SpringMVC文件上传

实现文件上传的前提

1.<form>表单的enctype属性取值必须是multipart/form-data(默认值是application/x-www-form-urlencoded),表示表单内容是分块的.这时request对象的getParameter()方法将失效.

2.<form>表单的method属性取值必须是post,因为get请求长度有限制.

3.提供一个<input/>标签,用来选择上传文件.
index.jsp

 <h3>传统文件上传</h3>

    <form action="/user/fileupload1" method="post" enctype="multipart/form-data">
        选择文件:<input type="file" name="upload" /><br/>
        <input type="submit" value="上传" />
    </form>

导入jar包

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

文件上传的三种实现

使用JavaEE进行文件上传(非重点)

传统的JavaEE文件上传思路是通过解析request对象,获取表单中的上传文件项并执行保存.

/**
     * 文件上传
     *
     * @return
     */
    @RequestMapping("/fileupload1")
    public String fileuoload1(HttpServletRequest request) throws Exception {
        System.out.println("文件上传...");

        // 使用fileupload组件完成文件上传
        // 上传的位置
        String path = request.getSession().getServletContext().getRealPath("/uploads/");
        // 判断,该路径是否存在
        File file = new File(path);
        if (!file.exists()) {
            // 创建该文件夹
            file.mkdirs();
        }
        // 解析request对象,获取上传文件项
        DiskFileItemFactory factory = new DiskFileItemFactory();
        ServletFileUpload upload = new ServletFileUpload(factory);
        // 解析request
        List<FileItem> items = upload.parseRequest(request);
        // 遍历
        for (FileItem item : items) {
            // 进行判断,当前item对象是否是上传文件项
            if (item.isFormField()) {
                // 说明普通表单向
            } else {
                // 说明上传文件项
                // 获取上传文件的名称
                String filename = item.getName();
                // 把文件的名称设置唯一值,uuid
                String uuid = UUID.randomUUID().toString().replace("-", "");
                filename = uuid + "_" + filename;
                // 完成文件上传
                item.write(new File(path, filename));
                // 删除临时文件
                item.delete();
            }
        }
        return "success";
    }

使用SpringMVC进行单服务器文件上传

可以使用SpringMVC提供的文件解析器实现文件上传,在Spring容器中注入文件解析器CommonsMultipartResolver对象如下:
spring.xml

 <!--配置文件解析器对象-->
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <property name="maxUploadSize" value="10485760" />
    </bean>

只要在处理器方法的参数列表中定义一个与表单文件项同名的MultipartFile参数,就可以将上传的文件绑定到该MultipartFile对象上,调用其transferTo(File file)方法即可保存文件.

/**
     * SpringMVC文件上传
     */
    @RequestMapping("/fileupload2")
    public String fileupload2(HttpServletRequest request, MultipartFile upload) throws Exception {
        System.out.println("spring文件上传...");
        // 使用fileupload组件完成文件上传
        // 上传的位置
        String path = request.getSession().getServletContext().getRealPath("/uploads/");
        // 判断,该路径是否存在
        File file = new File(path);
        if (!file.exists()) {
            // 创建该文件夹
            file.mkdirs();
        }
        // 说明上传文件项
        // 获取上传文件的名称
        String filename = upload.getOriginalFilename();
        // 把文件的名称设置唯一值,uuid
        String uuid = UUID.randomUUID().toString().replace("-", "");
        filename = uuid + "_" + filename;
        // 完成文件上传
        upload.transferTo(new File(path, filename));
        return "success";
    }

使用SpringMVC进行跨服务器文件上传

我们可以引入jersey库进行服务器间通信,实现将文件上传到一个专用的文件服务器,需要在pom.xml中引入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>

在处理器方法中创建Client对象实现服务器间通信,将文件上传到文件服务器上,代码如下:

 /**
     * 跨服务器文件上传
     *
     * @return
     */
    @RequestMapping("/fileupload3")
    public String fileupload3(MultipartFile upload) throws Exception {
        System.out.println("服务器文件上传...");
        // 定义上传文件服务器路径
        String path = "http://localhost:9090/fileupload_war_exploded/uploads/";
        // 说明上传文件项
        // 获取上传文件的名称
        String filename = upload.getOriginalFilename();
        // 把文件的名称设置唯一值,uuid
        String uuid = UUID.randomUUID().toString().replace("-", "");
        filename = uuid + "_" + filename;
        // 创建客户端的对象
        Client client = Client.create();
        // 和图片服务器进行连接
        WebResource webResource = client.resource(path + filename);
        // 上传文件
        webResource.put(upload.getBytes());
        return "success";
    }

异常处理器和拦截器

异常处理器

当程序发生错误时,错误最终会传递给DispatcherServlet,由DispatcherServlet进行异常处理.
下面演示使用SpringMVC的异常处理机制处理异常
1.创建自定义异常类

package cn.maoritian.exception;

public class SysException extends Exception {

    // 存储提示信息的
    private String message;

    // 构造方法
    public SysException(String message) {this.message = message; }

    // get,set方法
    public String getMessage() {return message; }
    public void setMessage(String message) {this.message = message; }
}

2.创建异常处理器,异常处理器必须实现HandlerExceptionResolver接口,其resolveException()方法执行异常处理.

package cn.maoritian.exception;

// 自定义异常处理器
public class MyExceptionResolver implements HandlerExceptionResolver {

    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {

        myException e = null;
        if (ex instanceof myException) {
            e = (myException) ex;
        } else {
            e = new myException("其他错误");
        }
        
        ModelAndView mv = new ModelAndView();
        mv.addObject("errorMsg", e.getMessage());   // 封装错误信息
        mv.setViewName("error");                    // 跳转页面
        return mv;
    }
}

向Spring容器中注入异常处理器

<!--配置异常处理器-->
    <bean id="sysExceptionResolver" class="cn.itcast.exception.SysExceptionResolver"/>

拦截器

拦截器的配置

SpringMVC中的拦截器只能拦截Controller中的方法,下面演示拦截器的使用
自定义拦截器需要继承HandlerInterceptor接口,该接口中定义了三个方法,都已有其默认实现:
preHandle(…): 该方法在处理器方法实际执行之前执行
postHandle(…): 该方法在处理器方法实际执行完毕以后执行
afterCompletion(…): 该方法在整个请求处理完成后执行

其中preHandle(…)方法返回一个boolean值,可以通过这个方法来决定是否继续执行处理链中的部件。当方法返回 true时,处理器链会继续执行;若方法返回 false, DispatcherServlet即认为拦截器自身已经完成了对请求的处理(比如说,已经渲染了一个合适的视图),那么其余的拦截器以及执行链中的其他处理器就不会再被执行了。

/**
 * 自定义拦截器
 */
public class MyInterceptor1 implements HandlerInterceptor{

    /**
     * 预处理,controller方法执行前
     * return true 放行,执行下一个拦截器,如果没有,执行controller中的方法
     * return false不放行
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws Exception
     */
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("MyInterceptor1执行了...前1111");
        // request.getRequestDispatcher("/WEB-INF/pages/error.jsp").forward(request,response);
        return true;
    }

    /**
     * 后处理方法,controller方法执行后,success.jsp执行之前
     * @param request
     * @param response
     * @param handler
     * @param modelAndView
     * @throws Exception
     */
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("MyInterceptor1执行了...后1111");
        // request.getRequestDispatcher("/WEB-INF/pages/error.jsp").forward(request,response);
    }

    /**
     * success.jsp页面执行后,该方法会执行
     * @param request
     * @param response
     * @param handler
     * @param ex
     * @throws Exception
     */
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("MyInterceptor1执行了...最后1111");
    }
}

向Spring容器中注入拦截器

    <!--配置拦截器-->
    <mvc:interceptors>
        <mvc:interceptor>
            <!--要拦截的方法-->
            <mvc:mapping path="/user/*"/>
            <!--不要拦截的方法-->
            <!--<mvc:exclude-mapping path=""/>-->
            <!--配置拦截器的对象-->
            <bean class="cn.itcast.interceptor.MyInterceptor1"></bean>
        </mvc:interceptor>
    </mvc:interceptors>
发布了33 篇原创文章 · 获赞 0 · 访问量 495

猜你喜欢

转载自blog.csdn.net/naerjiajia207/article/details/103515731
今日推荐