复习:springmvc三个作用—从页面获取数据

一、响应数据以及结果视图

昨天从原理图中得到一个结论—只需要编写处理器以及页面即可。
编写一个方法就是一个处理器,昨天的关注点在如何获取数据上。
编写一个方法,这个方法到底有多少种返回值类型。
image.png

1、String类型

  1. 返回string类型表示需要跳转的页面的路径以及页面名称。是需要走视图解析器。<br /> 如果我们返回String类型,我们的数据应该如何传递?可以传递数据
@RequestMapping("/view02")
    public String view02(Model model){
        model.addAttribute("name","李四");
        return "b";
    }

以上返回String类型的值其实是将Model 和 View 拆分开了,当我们需要给页面传递值得时候,我们就定义个Model model,如果不需要给页面传递值,只需要跳转页面,就不定义Model 即可,使用起来更加的灵活,所以可以替代ModelAndView

2、void类型

总结:
1) 每一个处理器中的方法,除了基本数据类型,String类型以及实体类型还有集合之外,还可以传递req以及resp
image.png
request以及response这两个变量可以只出现一个,也可以出现两个,也可以都不出现。
如果项目中使用到了该对象,需要导入servlet-api以及jsp的jar包

<!--加这两个的目的是HttpServletRequest  Response这两个类-->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
            <version>2.5</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>javax.servlet.jsp</groupId>
            <artifactId>jsp-api</artifactId>
            <version>2.0</version>
            <scope>provided</scope>
        </dependency>

2) 返回是void 类型,我们可以通过req中的内部转发的方式跳转页面,但是该方式跳转的页面不走视图解析器

@RequestMapping("/show01")
    public void show01(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        System.out.println("进入show01");
        //  该页面正确访问,说明req内部转发的url是不经过视图解析器的

        req.getRequestDispatcher("a.jsp").forward(req,resp);
    }

    @RequestMapping("/show02")
    public void show02(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("进入show02");
        // b页面不能正常访问,说明此方式不走视图解析器
        req.getRequestDispatcher("b").forward(req,resp);
    }

3)返回值是void类型,跳转页面也可以通过resp的重定向的方式,也是不走视图解析器,但是无法访问WEB-INF下的资源

3、返回值类型是ModelAndView

ModelAndView 其实就是一个类,里面可以通过方法存放数据以及视图名字,走视图解析器,并且页面可以通过el表达式获取数据

@Controller
public class Demo02Controller {

    @RequestMapping("/view01")
    public ModelAndView view01(){
        ModelAndView modelAndView = new ModelAndView();
        // 在该对象中,填充数据以及视图
        modelAndView.addObject("name","张三");
        modelAndView.setViewName("b");
        return modelAndView;
    }
}

二、重定向和内部转发

通过以上案例我们基本知道SpringMVC中如何进行重定向和内部转发,但是以上做法有一些不足:
我们需要引入HttpServletRequest以及Response对象,还需要引入jar包,而且编写代码也比较繁琐,Spring帮助我们升级了重定向和内部转发的写法。
总结:
springmvc帮助我们简化了重定向和内部转发的写法,无需req和resp对象,也不需要导入jar包
写法:
重定向: “redirect:/路径” , 不可以访问WEB-INF下的内容
内部转发: “forward:/路径” 可以访问WEB-INF下的内容

@Controller
public class Demo03Controller {
    @RequestMapping("/showPage01")
    public String showPage(){
        // springmvc的重定向,起作用了,说明此种方法进行重定向是没有问题的
        return "redirect:/a.jsp";
    }

    @RequestMapping("/showPage02")
    public String showPage2(){
        // springmvc的重定向,没有访问到资源,说明这种重定向的方式也是无法访问web-inf下的资源的
        return "redirect:/WEB-INF/page/b.jsp";
    }

    @RequestMapping("/showPage03")
    public String showPage3(){
        // springmvc的内部转发,起作用了,说明内部转发没有问题,而且也说明内部转发可以访问web-inf下的资源
        return "forward:/WEB-INF/page/b.jsp";
    }

    @RequestMapping("/showPage04")
    public String showPage4(){
        // springmvc的内部转发,起作用了,说明内部转发没有问题
        return "forward:/a.jsp";
    }
}

三、通过ResponseBody 响应 Json数据(响应Ajax请求)

1、编写一个页面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>使用ajax完成登录功能</title>
    <script src="${pageContext.request.contextPath}/js/jquery-1.8.3.min.js"></script>
    <script>
        function ajaxLogin(){

            var userName= $("#username").val();
            var password= $("#password").val();
            $.post("${pageContext.request.contextPath}/login",{"name":userName,"password":password},function(data){
                alert(data);
            });

            return false;//阻止事件冒泡== 让原来的button不提交表单
        }
    </script>
</head>
<body>

      用户名:<input id="username" type="text" name="username"/><br/>
      密码:<input id="password" type="password" name="password"/><br/>
      <input type="button" value="登录" onclick="return ajaxLogin()"/>

</body>
</html>

2、编写需要响应的controller

@Controller
public class LoginController {

    @RequestMapping("/login")
    @ResponseBody// 不走视图解析器,如果是String,直接返回,如果是实体,将实体数据变为json数据
    public String login(String name,String password){
        if(name.equals("laoyan")&&password.equals("root")){
            return "success";
        }else{
            return "fail";
        }
    }
}

3、当你需要引入一些静态资源的时候有两种写法
在springmvc中

<!--当我们需要引入一些静态资源的时候,springmvc中的前端控制器,会拦截我们的静态资源,需要放行-->
    <!-- 一个指的是url一个指的是文件夹 -->
    <mvc:resources mapping="/js/**" location="/js/"/>
    <!--<mvc:resources mapping="/css/**" location="/css/"/>
    <mvc:resources mapping="/img/**" location="/img/"/>-->

第二种:

<!--放行所有静态资源,如果写这一个,上面的就不用写了,二选一-->
    <mvc:default-servlet-handler/>

总结:
@ResponseBody
两个作用
第一个作用:让返回值不走视图解析器
第二个作用:将数据变为json数据,如果是String,原样输出,不是json,如果是实体,会自动变为json数据
如果我们将返回值从String 变为 Result实体,出现了异常

html lang="en"><head><title>HTTP Status 500 – Internal Server Error</title><style type="text/css">h1 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:22px;} h2 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:16px;} h3 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:14px;} body {font-family:Tahoma,Arial,sans-serif;color:black;background-color:white;} b {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;} p {font-family:Tahoma,Arial,sans-serif;background:white;color:black;font-size:12px;} a {color:black;} a.name {color:black;} .line {height:1px;background-color:#525D76;border:none;}</style></head><body><h1>HTTP Status 500 – Internal Server Error</h1><hr class="line" /><p><b>Type</b> Exception Report</p><p><b>Message</b> No converter found for return value of type: class com.qfedu.pojo.Result</p><p><b>Description</b> The server encountered an unexpected condition that prevented it from fulfilling the request.</p><p><b>Exception</b></p><pre>org.springframework.http.converter.HttpMessageNotWritableException: No converter found for return value of type: class com.qfedu.pojo.Result
    org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMethodProcessor.java:221)
    org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.handleReturnValue(RequestResponseBodyMethodProcessor.java:182)
    org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite.handleReturnValue(HandlerMethodReturnValueHandlerComposite.java:82)
    org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:119)
    org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:871)
    org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:777)
    org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
    org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:991)
    org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:925)
    org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:978)
    org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:881)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:661)
    org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:855)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:742)

出现以上的异常,是说Result实体无法转换为json数据,从而失败了。

package com.qfedu.pojo;

public class Result {
    private int code; // 0 表示成功, 1 表示用户名错误  2 表示密码错误  3 表示验证码错误  4 表示没有权限
    private String message;

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public String getMessage() {
        return message;
    }

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

需要导入jackson jar包,总共是三个

<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>
    </dependencies>

重点:如果返回值是一个实体类型,一定记得导入三个jackson的jar包

四、文件上传

使用springmvc自带的工具完成文件上传。
第一步:准备页面
必须是post请求,必须是多段式表单 enctype=”multipart/form-data”,必须有一个 file 输入框


<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>文件上传演示</title>
</head>
<body>
<!--每个表单都有一个类型,默认的类型 application/x-www-form-urlencoded-->
<form action="${pageContext.request.contextPath}/uploadImg" method="post" enctype="multipart/form-data">
    请上传您的帅照:<input type="file" name="imageFile"/>
    <input type="submit" value="提交"/>
</form>
</body>
</html>

第二步:编写Controller

@Controller
public class UploadController {

    @RequestMapping("/uploadImg")
    public String  upload(MultipartFile imageFile) throws IOException {
        File file = new File("C:/a.jpg");
        imageFile.transferTo(file);
        return "success";// 跳转到success页面
    }
}

第三步:需要导入文件上传需要的jar包

<!--文件上传所需的两个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>

第四步:需要配置文件上传解析器 springmvc.xml中

<!--此处的id必须等于multipartResolver 否则报错  配置文件上传解析器-->
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <property name="maxUploadSize">
            <!--设置文件上传最大的大小 5M-->
            <value>5242880</value>
        </property>
    </bean>

测试代码!
发现没有任何问题,图片上传成功!
修改版之后的文件上传!

@RequestMapping("/uploadImg")
    public String  upload(MultipartFile imageFile) throws IOException {

        // 动态获取后缀名
        String originalFilename = imageFile.getOriginalFilename();
        //  aaaa.png
        // 获取到字符串中,最后一个. 的下标位置
        int index = originalFilename.lastIndexOf(".");
        // 从某个坐标开始截取,截取到最后,返回一个新的字符串
        String suffix=originalFilename.substring(index);
        // 获取一个新的文件名字
        String fileName = UUIDUtils.getUUID()+suffix;


        File file = new File("C:/"+fileName);
        imageFile.transferTo(file);
        return "success";// 跳转到success页面
    }

五、通过tomcat搭建一个图片服务器

image.png
如何指定某个文件夹是tomcat的一个项目呢?
1、修改server.xml文件
在最后面的Hosts标签内,填写一个
docBase 存放你要存放的图片的文件夹 path 就是将来浏览器访问时候的虚拟路径名

2、修改该tomcat下的三个端口号。
3、一定要创建好文件夹
4、找一个图片,放进去,启动tomcat,通过浏览器访问
http://localhost:8081/images/a.jpg
image.png

六、springmvc的一个跨域上传

A Tomcat 跑的是java代码 —上传到—> B Tomcat 下
跨域访问: 百度去访问淘宝
localhost:80/xxxx/ 项目 localhost:8081/images/
IP地址,域名,以及端口只要有一个不一致,就叫跨域。
第一步:导入jar包

<!--处理跨域上传图片所需要的jar-->
        <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>

第二步:编写controller方法

// 跨域上传图片
    @RequestMapping("/uploadImg2")
    public String  upload2(MultipartFile imageFile) throws IOException {

        // 动态获取后缀名
        String originalFilename = imageFile.getOriginalFilename();
        //  aaaa.png
        // 获取到字符串中,最后一个. 的下标位置
        int index = originalFilename.lastIndexOf(".");
        // 从某个坐标开始截取,截取到最后,返回一个新的字符串
        String suffix=originalFilename.substring(index);
        // 获取一个新的文件名字
        String fileName = UUIDUtils.getUUID()+suffix;

        // 创建客户端
        Client client = Client.create();
        String path="http://localhost:8081/images/";
        //和图片服务器进行连接
        WebResource resource = client.resource(path + fileName);
        // 图片上传
        resource.put(imageFile.getBytes());
        return "success";// 跳转到success页面
    }

第三步:一定要修改tomcat图片服务器中的配置文件 在tomcat的 web.xml 中添加如下配置
因为默认的tomcat是不允许别人跨域访问资源的,所以需要如下配置才能解决

readonly
false

image.png

image.png

image.png