SpringMVC

SpringMVC

回顾Servlet

Servlet任务:

  • 获取前端请求参数
  • 调用业务层方法
  • 重定向/转发视图

demo

  • 环境配置

    新建普通Maven项目--->将src目录删除--->在项目中新建模块--->为该模块提供web框架支持--->导入要用到的依赖---->配置Tomcat

    • 导入依赖
    <dependencies>
        <!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.1</version>
            <scope>provided</scope>
        </dependency>
        <!-- https://mvnrepository.com/artifact/javax.servlet.jsp/javax.servlet.jsp-api -->
        <dependency>
            <groupId>javax.servlet.jsp</groupId>
            <artifactId>javax.servlet.jsp-api</artifactId>
            <version>2.3.3</version>
            <scope>provided</scope>
        </dependency>
        <!-- https://mvnrepository.com/artifact/javax.servlet/jstl -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.3.7</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.2</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
    
  • MyServlet

public class MyServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        /*1.获取前端传递的参数
        * 2.调用业务层的方法
        * 3.重定向/请求转发,刷新视图
        * */
        String method = req.getParameter("method");
        if("add".equals(method)) {
            req.getSession().setAttribute("msg","调用了add方法!");
        } else if("delete".equals(method)) {
            req.getSession().setAttribute("msg","调用了delete方法!");
        } else {
            req.getSession().setAttribute("msg","没有调用方法!");
        }
        req.getRequestDispatcher("WEB-INF/jsp/test.jsp").forward(req,resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}
  • test.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
${msg}
</body>
</html>

  • 在web.xml中注册Servlet
<servlet>
    <servlet-name>myServlet</servlet-name>
    <servlet-class>com.bin.servlet.MyServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>myServlet</servlet-name>
    <url-pattern>/hello</url-pattern>
</servlet-mapping>

SpringMVC执行原理(重点)

(面试会问)

中央控制器在一次请求响应的过程起到调度的作用。

前半部分实际上是在寻找确切的处理器的过程。

处理映射器-->中央控制器-->处理器适配器-->处理器

后半部分是对从处理器得到结果(ModelAndView)进行一个处理。

处理器-->处理适配器-->中央控制器-->视图解析器

Hello SpringMVC!

  • 配置环境
    • 导入以上的依赖
  • web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <servlet>
        <servlet-name>springmvc</servlet-name>
        <!--中央控制器-->
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <!--资源路径-->
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:springmvc-servlet.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>springmvc</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>
  • springmvc-servlet.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!--映射处理器-->
    <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
    <!--处理器适配器-->
    <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
    <!--视图解析器-->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!--视图解析规则-->
        <property name="prefix" value="/WEB-INF/jsp/"/>
        <property name="suffix" value=".jsp"/>
    </bean>
    <!--处理器(后端控制器)-->
    <bean id="/hello" class="com.bin.controller.MyController"/>

</beans>
  • MyController
//处理器,后端控制器
public class MyController implements Controller {
    public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
        ModelAndView mv = new ModelAndView();
        mv.addObject("msg","Hello SpringMVC!");
        mv.setViewName("test");
        return mv;
    }
}
  • test.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
${msg}
</body>
</html>

常见问题

404

  • 确定所导的包没有问题

使用注解开发

恭喜发现新大陆,使用注解开发会大大提高开发效率!

现在再来一遍,重新写一遍Hello,SpringMVC!

  • web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <servlet>
        <servlet-name>dipatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:springmvc-servlet.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>dipatcherServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>
  • springmvc-servlet.xml
<!--固定配置,开发中可以直接照搬-->
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/mvc
       http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <!--扫描到的包都有注解支持-->
    <context:component-scan base-package="com.bin.controller"/>
    <mvc:annotation-driven/>
    <mvc:default-servlet-handler/>

    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="WEB-INF/jsp/"/>
        <property name="suffix" value=".jsp"/>
    </bean>

</beans>
  • MyController
@Controller  //Controller声明
public class MyController {
    @RequestMapping("/test") //请求路径
    public String test(Model model) {
        //渲染前端
        model.addAttribute("msg","欢迎使用SpringMVC的注解!");
        //会经过视图解析器,变成WEB-INF/jsp/test.jsp
        return "test";
    }
}
  • test.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
${msg}
</body>
</html>

小结

  • 要想实现层级关系的URL,可以利用@Controller的属性进行设置,例如:@Controller("/docs")

由于该注解是修饰类的,该类下的所有方法成为该类的URL的子关系:http://localhost:8080/docs/test

  • 与Servlet相比,这里可以用更精简的代码实现相同的功能。

接收请求参数和数据回显

接收请求参数

在JavaWeb阶段,Servlet如何获取请求参数?

请求传递参数的方式:

  • 表单
  • 地址栏追加?param=value

通过req.getParameter("param")即可获取请求参数。

在SpringMVC阶段

只需:在控制器的方法参数列表添加对应的参数名和参数类型即可

@Controller
@RequestMapping("/pc")
public class ParameterController {
    @RequestMapping("/t1")
    public String test01(@RequestParam("name") String name, Model model) {
        model.addAttribute("msg",name);
        return "test";
    }
}
//@RequestParam:注解表明该参数是用于接收请求参数,其中属性代表请求参数中的参数名

数据回显

在JavaWeb阶段,如何进行数据回显?

request.setAttribute("name",value),然后请求转发

在SpringMVC阶段,可以使用Model进行

@Controller
@RequestMapping("/pc")
public class ParameterController {
    @RequestMapping("/t1")
    //同样在参数列表中添加Model对象
    public String test01(@RequestParam("name") String name, Model model) {
        //添加属性即可
        model.addAttribute("msg",name);
        return "test";
    }
}

RestFul风格

RestFul是一种资源定位和资源操作的风格,不是标准也不是协议,而是一种风格,基于该风格设计的软件 会更有层次感,更容易实现缓存机制。

功能

资源:互联网所有事物都可以被抽象为资源

资源操作:使用POST、DELETE、PUT、GET,使用不同方法对资源进行操作

分别对应增删改查。

传统方式操作资源

通过不同参数来操作资源,方法单一,只有get和post

http://127.0.0.1/item/additem.action 新增 get

http://127.0.0.1/item/deletitem.action?id=1 删除 post或get

http://127.0.0.1/item/updateitem.action 更新post

http://127.0.0.1/item/selectitem.action?id=1 查询 post

使用RestFul风格来操作资源

以下URL地址可能一样,但是功能可以完全不同

http://127.0.0.1/item POST增

http://127.0.0.1/item/1 DELETE删

http://127.0.0.1/item PUT改

http://127.0.0.1/item/1 GET查

实现

利用SpringMVC的URL模板模式

注解@PathVariable

@GetMapping("/owners/{ownerId}/pets/{petId}")
public String findPet(@PathVariable String ownerId, @PathVariable String petId, Model model) {
    Owner owner = ownerService.findOwner(ownerId);
    Pet pet = owner.getPet(petId);
    model.addAttribute("pet", pet);
    return "displayPet";
}

测试

  • MyController
@Controller
public class MyController02 {
    @RequestMapping(value = "/commit/{a}/{b}")
    //使用@PathVariable将方法参数的值绑定到URL模板变量上
    public String test01(@PathVariable int a, @PathVariable int b, Model model) {
        int res = a + b;
        model.addAttribute("msg","结果为:" + res);
        return "test";
    }
}
  • test.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
${msg}
</body>
</html>

修改参数类型

  • MyController
@Controller
public class MyController02 {
@RequestMapping(value = "/commit2/{a}/{b}")
    public String test02(@PathVariable String a, @PathVariable int b, Model model) {
        String res = a + b;
        model.addAttribute("msg","结果为:" + res);
        return "test";
    }
}

使用注解中的method属性指定请求类型

method属性可以收窄请求类型,常见属性如下。

GET,
HEAD,
POST,
PUT,
PATCH,
DELETE,
OPTIONS,
TRACE;

增加一个方法

@RequestMapping(value = "/hello",method = RequestMethod.POST)
public String test03(Model model) {
    model.addAttribute("msg","测试post");
    return "test";
}

此时使用地址栏访问,发现报错405

因为,用地址栏访问默认是用GET请求,将method的属性改为GET就好了

小结

@RequestMapping(value = "/hello",method = RequestMethod.POST)<======>@GetMapping("/hello")

同理

@RequestMapping(value = "/hello",method = RequestMethod.GET)<======>@GETMapping("/hello")

这两个较为常用。。。

重定向和转发

重定向:由客户端进行页面跳转,称之为重定向,客户端无法直接访问WEB-INF目录下的资源

转发:由服务端进行页面跳转,称之为转发

直接丢结论,SpringMVC默认是用转发

ModelController

@Controller
@RequestMapping("/mc")
public class ModelController {
    @RequestMapping("/t1")
    public String test01(Model model){
        model.addAttribute("msg","ModelController-->test01");
        return "test";
    }
}

原因很简单:因为视图解析器解析的是WEB-INF目录下资源,既然可以通过地址栏访问就说明肯定是用转发的方式。

那么,在SpringMVC中怎么实现重定向呢?

@RequestMapping("/t2")
public String test02(){
    //加上redirect:和绝对资源路径
    return "redirect:/rd.jsp";
}

乱码问题

在JavaWeb阶段,是怎么解决的?

过滤器。

在SpringMVC中,仍然选择过滤器,只不过这里的过滤器使用的是SpringMVC内置的过滤器,代表我们不要手动去写过滤器了,直接使用即可。

测试

  • CharacterEncodingController
@Controller
@RequestMapping("/c1")
public class CharacterEncodingController {
    @RequestMapping("t1")
    public String test01(@RequestParam("name")String name, Model model){
        System.out.println(name);
        model.addAttribute("msg",name);
        return "test";
    }
}
  • index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>$Title$</title>
  </head>
  <body>
  <form action="${pageContext.request.contextPath}/c1/t1" method="post">
    <input type="text" name="name">
    <input type="submit" value="提交">
  </form>
  </body>
</html>
  • test.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
${msg}
</body>
</html>

运行结果

解决方法

web.xml

<filter>
    <filter-name>characterEncoding</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
        <param-name>encoding</param-name>
        <param-value>UTF-8</param-value>
    </init-param>
    <init-param>
        <param-name>forceEncoding</param-name>
        <param-value>true</param-value>
    </init-param>

</filter>
<filter-mapping>
    <filter-name>characterEncoding</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

JSON

JSON:即"JavaScript Object Notation",JavaScript对象表示法,是一种轻量级的数据交换格式。

XML也是一种数据交换格式,那么为什么不用XML呢?

XML虽然可以作为跨平台的数据交换格式,但是XML中标签比数据多,增加了交换所产生的流量,而JSON没有附加额外的标记,且在JavaScript中可以作为对象处理,所以更倾向于用JSON来处理。

本质

字符串<=======>JavaScript对象相互转换的过程

<script>
    <!--定义js对象-->
    var user = {name:"zhangsan", age:3,sex:"男"};
    <!--js对象转字符串-->
    var strUser = JSON.stringify(user);
    <!--字符串转js对象-->
    var user2 = JSON.parse(strUser);
    console.log(user);
    console.log("===============")
    console.log(strUser);
    console.log("===============")
    console.log(user2)
</script>

Java对象转换成JSON字符串的方法

后端数据要响应到前端,需要做的事情之一就是将Java对象转换成字符串。

怎么做呢?

利用FastJson

  • User
public class User {
    private String name;
    private int age;
    private String sex;

    public User() {
    }

    public User(String name, int age, String sex) {
        this.name = name;
        this.age = age;
        this.sex = sex;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", sex='" + sex + '\'' +
                '}';
    }
}
  • JsonController
@RestController  //该注解可以让该控制器不去找视图解析器
@RequestMapping("/jc")
public class JsonController {
    @RequestMapping("/t1")
    public String test01() {
        User user = new User("小斌1", 1, "男");
        String userstr = JSON.toJSONString(user);
        //单个对象转换成Json字符串的情况
        return userstr;
    }
    @RequestMapping("/t2")
    public String test02() {
        ArrayList<User> userList = new ArrayList<User>();
        User user1 = new User("小斌1", 1, "男");
        User user2 = new User("小斌2", 1, "男");
        User user3 = new User("小斌3", 1, "男");
        userList.add(user1);
        userList.add(user2);
        userList.add(user3);
		//列表转换为Json字符串
        String userListStr = JSON.toJSONString(userList);
        return userListStr;
    }
    @RequestMapping("/t3")
    public String test03() {
        Date date = new Date();
        //时间以特定格式转换为Json字符串
        String dateStr = JSON.toJSONString(JSON.toJSONStringWithDateFormat(date,"yyyy-MM-dd HH-mm-ss"));
        return dateStr;
    }
}

进行该测试可能会出现的问题:

乱码问题:Json字符串带中文,到网页上是乱码。

解决:

在springmvc-servlet.xml中添加:

<mvc:annotation-driven>
    <mvc:message-converters register-defaults="true">
        <bean class="org.springframework.http.converter.StringHttpMessageConverter">
            <property name="supportedMediaTypes">
                <list>
                    <value>text/html;charset=UTF-8</value>
                    <value>application/json;charset=UTF-8</value>
                </list>
            </property>
        </bean>
    </mvc:message-converters>
</mvc:annotation-driven>

Ajax

简介

Ajax是一种Web数据交换方式,使用Ajax网页的技术可以快速地将增量更新呈现在用户界面上,而不需要重载(刷新)整个页面,这使得程序能够更快地回应用户的操作,可以大大提升用户体验!

按照原有的思路,如果想更新视图,首先得有个请求,比如:点击QQ动态这个动作,发起请求,请求经过中央控制器-->处理映射器-->中央控制器--->处理适配器--->处理器,通过处理器调用业务层方法得到数据,确定返回的视图,经过视图解析器,将数据渲染到前端。

但是业务逻辑并不是总是需要刷新新页面的,用户可能只是需要一小部分数据,而刷新整个页面就显得有点笨重了。

本质

利用JSON传递数据,将更多控制权交给了前端,此时,既然不需要视图刷新,那么就得想方设法“绕开”视图解析器,可以使用@RestController,粗略理解为,让Controller休息,哈哈哈哈。

另一一个问题,怎么使用Ajax?

拿出一个Ajax的例子

<!--发现实质上也是JSON数据-->
$.ajax({
url:"${pageContext.request.contextPath}/a1",
data:{"urlName":$("#urlName").val()},
success:function (data) {
console.log(data);
}
});

Ajax在SpringMVC中的使用

配置环境

前端框架jQuery:

  • 本地:
<script src="${pageContext.request.contextPath}/statics/js/jquery-3.4.1.js"></script>
  • CDN:
<script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>

新建普通Maven项目-->导入依赖-->导入框架支持-->添加lib目录添加包-->建骨架

  • 依赖
<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>5.3.7</version>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.13.2</version>
        <scope>test</scope>
    </dependency>
    <!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>4.0.1</version>
        <scope>provided</scope>
    </dependency>
        <!-- https://mvnrepository.com/artifact/javax.servlet.jsp/javax.servlet.jsp-api -->
        <dependency>
            <groupId>javax.servlet.jsp</groupId>
            <artifactId>javax.servlet.jsp-api</artifactId>
            <version>2.3.3</version>
            <scope>provided</scope>
        </dependency>
        <!-- https://mvnrepository.com/artifact/javax.servlet/jstl -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>
    
    <!--解决406问题-->
    <!-- https://mvnrepository.com/artifact/org.codehaus.jackson/jackson-mapper-asl -->
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-annotations</artifactId>
        <version>2.9.8</version>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-core</artifactId>
        <version>2.9.8</version>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.9.8</version>
    </dependency>
</dependencies>
  • web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">

    <servlet>
        <servlet-name>dispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:applicationContext.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>dispatcherServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

    <filter>
        <filter-name>characterEncodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>utf-8</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>characterEncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
</web-app>
  • applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       https://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/mvc
       http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <context:component-scan base-package="com.ice.controller"/>
    <mvc:annotation-driven>
        <mvc:message-converters register-defaults="true">
            <bean class="org.springframework.http.converter.StringHttpMessageConverter">
                <property name="supportedMediaTypes">
                    <list>
                        <value>text/html;charset=UTF-8</value>
                        <value>application/json;charset=UTF-8</value>
                    </list>
                </property>
            </bean>
        </mvc:message-converters>
    </mvc:annotation-driven>
    <!--静态资源过滤-->
    <mvc:default-servlet-handler/>

    <bean id="contentNegotiationManager" class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
        <property name="favorPathExtension" value="false"/>
        <property name="favorParameter" value="false"/>
        <property name="ignoreAcceptHeader" value="false"/>
        <property name="mediaTypes">
            <value>
                atom = application/atom+xml
                html = text/html
                json = application/json
                * = */*
            </value>
        </property>
    </bean>

    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/jsp/"/>
        <property name="suffix" value=".jsp"/>
    </bean>
</beans>

Demo1

输入框失去焦点后,打印台会根据输入的内容打印“地址错误”或“地址正确”!

  • index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
    <head>
        <title>$Title$</title>
        <!--引入jQuery-->
        <script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
        <script>
            function a1(){
                $.ajax({
                    url:"${pageContext.request.contextPath}/a1",
                    data:{"urlName":$("#urlName").val()},
                    success:function (data) {
                        console.log(data);
                    }
                });
            }
        </script>
    </head>
    <body>
        <div>
            <p>
            <form action="#" name="form1">
                <!--失去焦点,调用函数-->
                <input type="text" id="urlName" name="urlName" value="" onblur="a1()"/>
            </form>
            </p>
        </div>
    </body>
</html>
  • AjaxController
@RestController //
public class AjaxController {
    @RequestMapping("/a1")
    public void test01(String urlName, HttpServletResponse response) throws IOException {
        System.out.println(urlName);
        response.setCharacterEncoding("UTF-8");
        if("www.baidu.com".equals(urlName)){
            response.getWriter().write("地址正确");
        } else
            response.getWriter().write("地址错误");
    }
}

Demo2

点击获取数据按钮后,会在不转发或重定向的情况下模拟将数据库中查询到的数据更新到前端页面。

  • test02.jsp
<html>
<head>
    <title>Title</title>
    <script src="${pageContext.request.contextPath}/statics/js/jquery-3.4.1.js"></script>
    <script>
        function a2(){
            $.ajax({
                url:"${pageContext.request.contextPath}/a2",
                <!--请求成功的回调函数,会携带数据-->
                success:function (data){
                    console.log(data)
                    var html1="";
                    for (let i = 0; i < data.length; i++) {
                        html1 += "<tr>" +
                            "<td>" + data[i].songID + "</td>" +
                            "<td>" + data[i].songName + "</td>" +
                            "<td>" + data[i].songDetail + "</td>" +
                            "</tr>";
                    }
                    document.getElementById("content").innerHTML = html1;

                }
            })
        }
    </script>
</head>
<body>
    <!--触发点击事件-->
<input type="button" id="getData" value="获取数据" onclick="a2()"/>
<table>
    <tr>
        <td>编号</td>
        <td>歌名</td>
        <td>专辑</td>
    </tr>
    <tbody id="content">

    </tbody>
</table>

</body>
</html>
  • AjaxController
@RequestMapping("/a2")
public List<Song> test02(){
    List<Song> songsList = new ArrayList<Song>();
    songsList.add(new Song(1,"《斗牛》","《Jay》"));
    songsList.add(new Song(2,"《娘子》","《Jay》"));
    songsList.add(new Song(3,"《星晴》","《Jay》"));
    //传递一个列表
    return songsList;
}

Demo3

模拟用户密码框动态验证的功能,如果用户名或密码错误,会实时给出提示信息。

  • login.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
    <head>
        <title>Title</title>
        <script src="${pageContext.request.contextPath}/statics/js/jquery-3.4.1.js"></script>
        <script>
            function a3(){
                $.ajax({
                    url:"${pageContext.request.contextPath}/a3",
                    data:{"userName":$("#userName").val()},
                    success:function (data){
                        console.log(data);
                        $("#userInfo").html(data);
                        if ("√" === data.toString()){
                 		    <!--更新css-->
                            $("#userInfo").css("color","green");
                        } else{
                            $("#userInfo").css("color","red");
                        }
                    }
                })
            }
            function a4(){
                $.ajax({
                    url:"${pageContext.request.contextPath}/a3",
                    data:{"password":$("#password").val()},
                    success:function (data){
                        console.log(data);
                        $("#pwdInfo").html(data);
                        if ("√" === data.toString()){
                            $("#pwdInfo").css("color","green");
                        } else{
                            $("#pwdInfo").css("color","red");
                        }
                    }
                })
            }
        </script>
    </head>
    <body>
        <p>用户名:<input type="text" id="userName" onblur="a3()"/> <span id="userInfo"></span></p>
        <p>密码:<input type="password" id="password" onblur="a4()"/> <span id="pwdInfo"></span></p>
    </body>
</html>

  • AjaxController
@RequestMapping("/a3")
public String test03(String userName,String password){
    System.out.println(userName);
    String msg = "√";
    if(userName != null)
        if(!"admin".equals(userName)){
            msg = "用户名有误!";
        }
    if(password != null)
        if (!"root".equals(password)){
            msg = "密码有误!";
        }
    //传递msg
    return msg;
}

拦截器

在JavaWeb阶段,也有类似的东西存在:只不过叫做过滤器,但其实都差不多。

在SpringMVC中,称之为拦截器。

拦截器在网页开发中挺常见的:比如,想设置一个拦截器,实现未登录的用户无法进入特定页面,要想进入特定页面,得先登录。

Demo

  • index.jsp
<body>
    <p><a href="${pageContext.request.contextPath}/user/toLogin">登录</a></p>
    <p><a href="${pageContext.request.contextPath}/user/main">首页</a></p>
</body>
  • /WEB-INF/jsp/login.jsp
<body>
    <form action="${pageContext.request.contextPath}/user/login">
        <p>用户名:<input type="text" name="username"></p>
        <p>密&nbsp;码:<input type="password" name="password"></p>
        <p><input type="submit"></p>
    </form>
</body>
  • /WEB-INF/jsp/main.jsp
<body>
<h1>当前页面:首页</h1>
</body>
  • UserController
@Controller
@RequestMapping("/user")
public class UserController {
    @RequestMapping("/toLogin")
    public String toLogin() {
        return "login";
    }

    @RequestMapping("/main")
    public String toMain(){
        return "main";
    }

    @RequestMapping("/login")
    public String login(String username, String password, HttpServletRequest request){
        //将用户名存到Session中
        request.getSession().setAttribute("username",username);
        return "main";
    }
  • UserInterceptor
public class UserInterceptor implements HandlerInterceptor {
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
       //若session中有用户信息就放行,没有则转发到登录页面
        if (request.getSession().getAttribute("username") != null) {
            System.out.println("已登录,用户名为" + request.getSession().getAttribute("username"));
            return true;
        } else {
            System.out.println("未登录,被拦截了!");
            //请求转发
            request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request,response);
        }

        return true;
    }
}
  • applicationContext.xml
<mvc:interceptors>
    <mvc:interceptor>
        <mvc:mapping path="/user/main"/>
        <bean class="com.ice.interceptor.UserInterceptor"/>
    </mvc:interceptor>
</mvc:interceptors>

文件上传

1、导入文件上传的jar包,commons-fileupload , Maven会自动帮我们导入他的依赖包 commons-io包;

<!--文件上传-->
<dependency>
   <groupId>commons-fileupload</groupId>
   <artifactId>commons-fileupload</artifactId>
   <version>1.3.3</version>
</dependency>
<!--servlet-api导入高版本的-->
<dependency>
   <groupId>javax.servlet</groupId>
   <artifactId>javax.servlet-api</artifactId>
   <version>4.0.1</version>
</dependency>

2、配置bean:multipartResolver

注意!!!这个bena的id必须为:multipartResolver , 否则上传文件会报400的错误!在这里栽过坑,教训!

<!--文件上传配置-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
   <!-- 请求的编码格式,必须和jSP的pageEncoding属性一致,以便正确读取表单的内容,默认为ISO-8859-1 -->
   <property name="defaultEncoding" value="utf-8"/>
   <!-- 上传文件大小上限,单位为字节(10485760=10M) -->
   <property name="maxUploadSize" value="10485760"/>
   <property name="maxInMemorySize" value="40960"/>
</bean>

CommonsMultipartFile 的 常用方法:

  • String getOriginalFilename():获取上传文件的原名
  • InputStream getInputStream():获取文件流
  • void transferTo(File dest):将上传文件保存到一个目录文件中

我们去实际测试一下

3、编写前端页面

<form action="/upload" enctype="multipart/form-data" method="post">
 <input type="file" name="file"/>
 <input type="submit" value="upload">
</form>

4、Controller

package com.kuang.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.commons.CommonsMultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.*;

@Controller
public class FileController {
   //@RequestParam("file") 将name=file控件得到的文件封装成CommonsMultipartFile 对象
   //批量上传CommonsMultipartFile则为数组即可
   @RequestMapping("/upload")
   public String fileUpload(@RequestParam("file") CommonsMultipartFile file ,HttpServletRequest request) throws IOException {

       //获取文件名 : file.getOriginalFilename();
       String uploadFileName = file.getOriginalFilename();

       //如果文件名为空,直接回到首页!
       if ("".equals(uploadFileName)){
           return "redirect:/index.jsp";
      }
       System.out.println("上传文件名 : "+uploadFileName);

       //上传路径保存设置
       String path = request.getServletContext().getRealPath("/upload");
       //如果路径不存在,创建一个
       File realPath = new File(path);
       if (!realPath.exists()){
           realPath.mkdir();
      }
       System.out.println("上传文件保存地址:"+realPath);

       InputStream is = file.getInputStream(); //文件输入流
       OutputStream os = new FileOutputStream(new File(realPath,uploadFileName));//文件输出流

       //读取写出
       int len=0;
       byte[] buffer = new byte[1024];
       while ((len=is.read(buffer))!=-1){
           os.write(buffer,0,len);
           os.flush();
      }
       os.close();
       is.close();
       return "redirect:/index.jsp";
  }
}

5、测试上传文件,OK!

采用file.Transto 来保存上传的文件

1、编写Controller

/*
* 采用file.Transto 来保存上传的文件
*/
@RequestMapping("/upload2")
public String  fileUpload2(@RequestParam("file") CommonsMultipartFile file,HttpServletRequest request) throws IOException {

   //上传路径保存设置
   String path = request.getServletContext().getRealPath("/upload");
   File realPath = new File(path);
   if (!realPath.exists()){
       realPath.mkdir();
  }
   //上传文件地址
   System.out.println("上传文件保存地址:"+realPath);

   //通过CommonsMultipartFile的方法直接写文件(注意这个时候)
   file.transferTo(new File(realPath +"/"+ file.getOriginalFilename()));

   return "redirect:/index.jsp";
}

2、前端表单提交地址修改

3、访问提交测试,OK!

文件下载

文件下载步骤:

1、设置 response 响应头

2、读取文件 -- InputStream

3、写出文件 -- OutputStream

4、执行操作

5、关闭流 (先开后关)

代码实现:

@RequestMapping(value="/download")
public String downloads(HttpServletResponse response ,HttpServletRequest request)throws Exception{
   //要下载的图片地址
   String  path = request.getServletContext().getRealPath("/upload");
   String  fileName = "基础语法.jpg";

   //1、设置response 响应头
   response.reset(); //设置页面不缓存,清空buffer
   response.setCharacterEncoding("UTF-8"); //字符编码
   response.setContentType("multipart/form-data"); //二进制传输数据
   //设置响应头
   response.setHeader("Content-Disposition",
           "attachment;fileName="+URLEncoder.encode(fileName, "UTF-8"));

   File file = new File(path,fileName);
   //2、 读取文件--输入流
   InputStream input=new FileInputStream(file);
   //3、 写出文件--输出流
   OutputStream out = response.getOutputStream();

   byte[] buff =new byte[1024];
   int index=0;
   //4、执行 写出操作
   while((index= input.read(buff))!= -1){
       out.write(buff, 0, index);
       out.flush();
  }
   out.close();
   input.close();
   return null;
}

前端

<a href="/download">点击下载</a>

测试,文件下载OK,大家可以和我们之前学习的JavaWeb原生的方式对比一下,就可以知道这个便捷多了!

posted @ 2021-06-08 22:31  Code_Ice  阅读(52)  评论(0)    收藏  举报