SpringMVC ~ 从入门到入坑。
文章目录
三层架构。
技术。
Spring + SpringMVC + MyBatis。
MVC 设计模型。
https://mp.weixin.qq.com/s/yuQqZzAsCefk9Jv_kbh_eA
软件设计规范。
M ——> model 模型。JavaBean。(dao, Servlet)。
V ——> view 视图。JSP。(转发,重定向)。
C ——> controller 控制器。Servlet。
- VO 是什么。
前端 ——> 数据传输 ——> 实体类。
eg.
实体类:用户名、密码、生日、爱好、… (20 个)。
前端:只需要用户名和密码。
这里传给前端的数据不要用实体类封装(18 个 NULL)。
所以就出现了:VO(Visual Object)。——> UserVO。
- 模型演变。
model 1 时代。
jsp 本质就是一个 Servlet。
架构简单,适合小型项目。
JSP 职责不单一,不便于维护。
ps
你的项目构架,是设计好的,还是演进的?
演进。
Alibaba:PHP。
随着用户量增大,Java。
王坚 ——> 弃用 IOE(费用高)。——> MySQL。
MySQL ——> AliSQL、AliRedis。
model 2 时代。
- 项目架构演进。
All in one ——> 微服务。
Controller。控制器。
取得表单数据。
调用业务逻辑。
转向指定页面。
Model。模型。
业务逻辑。
保存数据的状态。
View。视图。
显示页面。
复习:从 Servlet 开始。
Maven 父工程。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.geek</groupId>
<artifactId>SpringMVCGeek</artifactId>
<version>1.0-SNAPSHOT</version>
<!-- 导入依赖。-->
<dependencies>
<!-- https://mvnrepository.com/artifact/junit/junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.servlet/servlet-api -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.servlet.jsp/jsp-api -->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.2</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>
</dependencies>
</project>
- 再新建一个 Maven 项目,都不使用
archetype
。(SpringMVCGeek 的子项目)。
创建好以后右键
,add framework support
。
自动创建 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">
</web-app>
此时项目结构。
配置 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>helloServlet</servlet-name>
<servlet-class>com.geek.servlet.HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>helloServlet</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
</web-app>
附加配置。(了解)。
<session-config>
<!-- 15 分钟。-->
<session-timeout>15</session-timeout>
</session-config>
<welcome-file-list>
<!-- 默认访问页面。-->
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
web 和 WEB-INF。
jsp。
放在 web 目录下。公共,用户可见。
放在 /web/WEB-INF 下,安全,用户不可见。
代码。
servlet。
package com.geek.servlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class HelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// super.doGet(req, resp);
// 获取前端参数。
String method = req.getParameter("method");
if ("add".equals(method)) {
req.getSession().setAttribute("msg", "执行了 add(); 方法。");
}
if ("post".equals(method)) {
req.getSession().setAttribute("msg", "执行了 delete(); 方法。");
}
// 调用业务层。
// 视图转发或重定向。
req.getRequestDispatcher("/WEB-INF/jsp/test.jsp").forward(req, resp);// 转发。
// resp.sendRedirect();// 重定向。
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// super.doPost(req, resp);
this.doGet(req, resp);
}
}
jsp。
放在 web 目录下。公共,用户可见。
放在 /web/WEB-INF 下,安全,用户不可见。
<%--
Created by IntelliJ IDEA.
User: geek
Date: 3/15/20
Time: 11:39 PM
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
${msg}
</body>
</html>
测试。
以上是我们在使用框架前自己干的事。这么没技术含量的事以后就交给框架吧。
- SpringMVC 要做什么。
将 url 映射到 Java 类或 Java 类的方法。
封装用户提交的数据。
处理请求,调用相关的业务处理,封装响应数据。
将响应的数据进行渲染,jsp / html 等表示层数据。
以前我们写,每个 Servlet 对应一个功能,如果功能多,就要写多个 Servlet。
SpringMVC 将中转、调度功能做到了极致。
—— 没有什么是加一层(架构)解决不了的。
调度:处理请求,适配 URL,跳转页面。
——> DispatcherServlet。
除了有 doGet(); doPost(); 方法,还加入了其他,eg. 适配器…。
SpringMVC 来了。
可以看到,DispatcherServlet
本质上是一个 GenericServlet
。(实现了 Setvlet 接口)。
SpringMVC 入门。
https://mp.weixin.qq.com/s/8ddT6FD0Y4f3XdbEz0aqpQ
配置。
一步一步来。
在以前的配置基础上改造。
把以前自己写的 Servlet 换成 SpringMVC 框架提供的 DispatcherServlet
。
<?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">
<!-- 注册 DispatcherServlet。-->
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<!--<servlet-class>com.geek.servlet.HelloServlet</servlet-class>-->
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>
<!-- / ——> 匹配所有的请求(不包括 .jsp)。-->
<!-- /* ——> 匹配所有的请求(包括 .jsp)。-->
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
↓ ↓ ↓
进一步,DispatcherServlet 在服务器启动时要读取配置文件 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">
<!-- 注册 DispatcherServlet。-->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 关联一个 springmvc 配置文件。【servlet_name】-servlet.xml-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc-servlet.xml</param-value>
<!-- classpath* ——> 会查找所有 jar 包的 classpath。-->
</init-param>
<!-- 启动级别 1。——> 和服务器一起启动。-->
<load-on-startup>1</load-on-startup>
</servlet>
<!-- / ——> 匹配所有请求。(不包括 .jsp)。-->
<!-- /* ——> 匹配所有请求。(包括 .jsp)。-->
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
在 resurces
目录下创建配置文件 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"/>
<!-- 真实开发使用注解替代。-->
<!-- 视图解析器。模板引擎:Thymeleaf, Freemarker。。。-->
<bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 拼接文件路径名。-->
<!-- 前缀。-->
<property name="prefix" value="/WEB-INF/jsp/"/>
<!-- 后缀。-->
<property name="suffix" value=".jsp"/>
</bean>
<!-- 核心 3 要素。-->
</beans>
- Class HelloController。(原理级,使用了 ModelAndView,真实开发不用)。
只有 ta 是我们自己写的。
package com.geek.controller;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class HelloController implements Controller {
@Override
public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
// modelAndView 视图和模型。
ModelAndView modelAndView = new ModelAndView();
// 封装对象。放在 ModelAndView 中。model。
modelAndView.addObject("msg", "HelloSpringMVC");
// 封装要跳转的视图。放在 ModelAndView 中。view。
modelAndView.setViewName("hello");// /WEB-INF/jsp/`hello`.jsp。
return modelAndView;
// return null;
}
}
因为使用了 BeanNameUrlHandlerMapping
处理器映射器,ta 是根据 bean 的 id 查找处理器映射器的,所以。。。
最后,将自己写的 Handler 交给 Spring 管理,赋予 id。
<?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"/>
<!-- 真实开发使用注解替代。-->
<!-- 视图解析器。以后:模板引擎:Thymeleaf,Freemarker。。。-->
<bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 拼接文件路径名。
/WEB-INF/jsp/`test`.jsp。
-->
<!-- 前缀。-->
<property name="prefix" value="/WEB-INF/jsp/"/>
<!-- 后缀。-->
<property name="suffix" value=".jsp"/>
</bean>
<!-- 核心 3 要素。-->
<!-- Handler。-->
<bean id="/hello" class="com.geek.controller.HelloController"/>
</beans>
<!-- 这里 id 必须为 `/hello`。否则 404。-->
</beans>
运行测试。
GG,404。
发现已知问题 3 点。
-
bean 的 id 必须为
/hello
。否则 404。 -
映射路径用
/
,而不用/*
。 -
WEB-INF 下没有依赖(lib)。
因为我们不是创建的 Web 项目,而是先创建空 Maven 项目,再 add framewoork support
,所以要在 Artifacts
中手动给 war 包添加 /lib
(亲测 /libs 无效)。
文件夹名必须为 lib
。
手动添加。
重启 Tomcat。
访问 localhost:8080/hello。
原理图。
eg. http://localhost:8080/SpringMVC/hello
- http://localhost:8080
服务器域名。- SpringMVC
部署在服务器上的 web 站点。- hello。
控制器。
请求位于服务器 localhost:8080 上的 SpringMVC 站点的 hello 控制器。
还是太麻烦。以上只是介绍原理。
来真的。annotation 上场。
annotation。
注意。
- web.xml 使用 4.0 版本。
- 因为我们不是创建的 Web 项目,而是先创建空 Maven 项目,再
add framewoork support
,所以要在Artifacts
中手动给 war 包添加/lib
(亲测 libs 无效)。
<?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">
<!-- 配置 DispatcherServlet。SpringMVC 的核心,请求分发器,前端控制器。-->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- DispatcherServlet 要绑定 SpringMVC 的配置文件。-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc-servlet.xml</param-value>
<!-- classpath* ——> 会查找所有 jar 包的 classpath。-->
</init-param>
<!-- 启动级别:1 ——> 和服务器一起启动。-->
<load-on-startup>1</load-on-startup>
</servlet>
<!--
SpringMVC 中,
/ ——> 只匹配所有的请求,不会匹配 .jsp 页面。
/* ——> 匹配所有的请求,包括 .jsp 页面。如果使用这个,视图解析器要拼接 .jsp,会无限 .jsp。
-->
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
注解方式的 springmvc-context.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">
<!--
处理器映射器。
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
处理器适配器。
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
真实开发不需要。注解替代。
-->
<!-- 自动扫描包。让指定包下的注解生效,给 Spring IoC 容器统一管理。-->
<context:component-scan base-package="com.geek"/>
<!-- 让 SpringMVC 不处理静态资源。.cs .js .html .mp3 .mp4-->
<mvc:default-servlet-handler/>
<!-- 支持 mvc 注解驱动。
在 Spring 中一般采用 @RequestMapping 注解来完成映射关系。
要想使 @RequestMapping 注解生效,
必须向上下文中注册 DefaultAnnotationHandlerMapping
和一个 AnnotationMethodHandlerAdapter 实例。
这两个实例分别在类级别和方法级别处理。
而 annotation-driver 配置帮助我们自动完成上述两个实例的注入。
-->
<mvc:annotation-driven/>
<!-- 视图解析器。以后:模板引擎:Thymeleaf,Freemarker。。。-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
<!-- 核心 3 要素。-->
<!--
Handler。
<bean id="/hello" class="com.geek.controller.HelloController"/>
这里 id 必须为 `/hello`。否则 404。-->
</beans>
在 Controller 类上使用注解。
如果要传 json 数据 ——> @RestController。
package com.geek.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
//@RestController// 不会被视图解析器解析,直接返回 json。
@Controller
@RequestMapping("/hello")
public class HelloController {
// localhost:8080/hello/h1
@RequestMapping("/h1")
public String hello(Model model) {
// 封装数据。
// 向模型中添加属性 msg 的值,可以在 jsp 页面中解析并取出。
model.addAttribute("msg", "Hello, SpringMVC Annotation.");
return "hello";// 被视图解析器处理。
}
}
真香。
小结。
- 新建一个 Web 项目。
- 导入相关 jar 包。
- 编写 web.xml,注册 DispatcherServlet。
- 编写 springmvc 配置文件。
- 创建对应的控制类 controller。
- 完善前端视图和 controller 之间的对应。
- 测试。
三大组件。
- 处理器映射器。(注解)。
- 处理器适配器。(注解)。
- 视图解析器。(手动)。
Controller 配置总结。
- 新建项目 / 模块。
- 导 jar 包。
- artifact 中加入
lib
。- Add Framework Support。
- web.xml 和 springmvc-context.xml
- Controller
controller 控制器相关问题。
https://mp.weixin.qq.com/s/3EtyzJohOVGz62nEYLhKHg
- 控制器负责提供访问应用程序的行为,通常通过接口定义或注解定义两种方法实现。
- 控制器负责解析用户的请求并将其转换为一个模型。
- 在 Spring MVC 中一个控制器类可以包含多个方法
- 在 Spring MVC 中,对于 Controller 的配置方式有很多种
方式 1。 实现 Controller 接口。
Controller 中,
实现 Controller 接口是较老办法。
org.springframework.web.servlet.mvc.Controller
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package org.springframework.web.servlet.mvc;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.lang.Nullable;
import org.springframework.web.servlet.ModelAndView;
@FunctionalInterface
public interface Controller {
@Nullable
ModelAndView handleRequest(HttpServletRequest var1, HttpServletResponse var2) throws Exception;
}
此时可以不要
<context:component-scan base-package="com.geek.controller"/>
<mvc:default-servlet-handler/>
<mvc:annotation-driven/>
而是配置 bean。
<bean name="/t1" class="com.geek.controller.ControllerDemo01"/>
缺点。
一个控制器中只能写一个方法。
package com.geek.controller;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 只要实现了 Controller 接口的类,说明这就是一个控制器了。
*/
public class ControllerDemo01 implements Controller {
@Override
public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("msg", "controllerDemo01");
modelAndView.setViewName("test");
return modelAndView;
// return null;
}
}
方式 2。 注解。
<?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.geek.controller"/>
<mvc:default-servlet-handler/>
<mvc:annotation-driven/>
<bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
<!--<bean name="/t1" class="com.geek.controller.ControllerDemo01"/>-->
</beans>
package com.geek.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller// 这个类被 Spring 接管。
// 被 ta 注解的类,中的所有方法,如果返回值是 String,并且有具体页面可以跳转,那么就会被视图解析器解析。
public class ControllerTest02 {
@RequestMapping("/t2")
public String test01(Model model) {
model.addAttribute("msg", "ControllerTest02");
return "test";
}
@RequestMapping("/t3")
public String test03(Model model) {
model.addAttribute("msg", "ControllerTest02~t3");
return "test";
// 共用一个页面。
}
/* @Override
public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("msg", "controllerDemo01");
modelAndView.setViewName("test");
return modelAndView;
// return null;
}*/
}
// 控制器和页面弱耦合。
- 为 url 分配 bean。(基本没用)。
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="/test">testController</prop>
</props>
</property>
</bean>
<bean id="testController" class="com.geek.controller.ControllerTest01"/>
package com.geek.controller;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
// 实现 Controller 接口的类可以获得控制器的功能。
public class ControllerTest01 implements Controller {
@Override
public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("msg", "ControllerTest01");
modelAndView.setViewName("test");
return modelAndView;
}
}
@RequestMapping。
用于映射 url 到控制器类或一个特定的处理程序方法,可用于类或方法上。
用于类上,表示类中的所有响应请求的方法都是以该 url 作为父路径。
http://localhost:8080/03/c3/t1
类中的所有方法就要加 /c3。
package com.geek.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("/c3")
public class ControllerTest03 {
@RequestMapping("/t1")
public String test01(Model model) {
model.addAttribute("msg", "ControllerTest03 ");
return "test";
}
}
RESTful 风格。
https://mp.weixin.qq.com/s/3EtyzJohOVGz62nEYLhKHg
REST(英文:Representational State Transfer,简称 REST)描述了一个架构样式的网络系统,比如 web 应用程序。ta 首次出现在 2000 年 Roy Fielding 的博士论文中,Roy Fielding 是 HTTP 规范的主要编写者之一。在目前主流的三种 Web 服务交互方案中,REST相比于 SOAP(Simple Object Access protocol,简单对象访问协议)以及 XML-RPC 更加简单明了,无论是对 URL 的处理还是对 Payload 的编码,REST 都倾向于用更加简单轻量的方法设计和实现。值得注意的是 REST 并没有一个明确的标准,而更像是一种设计的风格。
Restful 就是一个资源定位及资源操作的风格。不是标准也不是协议,只是一种风格。基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。
- 功能。
- 资源:互联网所有的事物都可以被抽象为资源。
- 资源操作:使用 POST、DELETE、PUT、GET,使用不同方法对资源进行操作。
- 分别对应 增加、删除、修改、查询。
- 对比。
传统方式操作资源 :通过不同的参数
来实现不同的效果!方法单一,post 和 get。
http://127.0.0.1/item/queryItem.action?id=1 ~ 查询,GET。
http://127.0.0.1/item/saveItem.action ~ 新增,POST
http://127.0.0.1/item/updateItem.action ~ 更新,POST。
http://127.0.0.1/item/deleteItem.action?id=1 ~ 删除,GET 或 POST。
使用 RESTful 操作资源:可以通过不同的请求方式
来实现不同的效果!如下:请求地址一样,但是功能可以不同!
http://127.0.0.1/item/1 ~ 查询,GET。
http://127.0.0.1/item ~ 新增,POST。
http://127.0.0.1/item ~ 更新,PUT。
http://127.0.0.1/item/1 ~ 删除,DELETE。
一般风格。
package com.geek.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class RESTfulController {
// http://localhost:8080/03/add?a=1&b=2
@RequestMapping("/add")
public String test00(int a, int b, Model model) {
System.out.println("a = " + a);
System.out.println("b = " + b);
// 名字必须一致。a 和 b 顺序可以不同。
// http://localhost:8080/03/add?b=2&a=1
int res = a + b;
model.addAttribute("msg", "结果为 " + res);
return "test";
}
}
@PathVariable ~ RESTFul 风格。
package com.geek.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class RESTfulController {
// http://localhost:8080/03/add/1/2
@RequestMapping("/add/{a}/{b}")
public String test01(@PathVariable int a, @PathVariable int b, Model model) {
System.out.println("a = " + a);
System.out.println("b = " + b);
// 名字必须一致。a 和 b 顺序可以不同。
// @RequestMapping("/add/{b}/{a}")
// http://localhost:8080/03/add/1/2
// a = 2, b = 1
// int 可以改为 String。
int res = a + b;
model.addAttribute("msg", "结果为 " + res);
return "test";
}
}
@PathVariable ~ method 参数。
package com.geek.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@Controller
public class RESTfulController {
/*
HTTP Status 405 – Method Not Allowed
Type Status Report
Message Request method 'GET' not supported
Description The method received in the request-line is known by the origin server but not supported by the target resource.
Apache Tomcat/8.5.53
*/
// http://localhost:8080/03/add/1/2
@RequestMapping(value = "/add/{a}/{b}", method = RequestMethod.DELETE)
public String test01(@PathVariable int a, @PathVariable int b, Model model) {
System.out.println("a = " + a);
System.out.println("b = " + b);
// 名字必须一致。a 和 b 顺序可以不同。
// @RequestMapping("/add/{b}/{a}")
// http://localhost:8080/03/add/1/2
// a = 2, b = 1
// int 可以改为 String。
int res = a + b;
model.addAttribute("msg", "结果为 " + res);
return "test";
}
}
alias。
package com.geek.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@Controller
public class RESTfulController {
// http://localhost:8080/03/add/1/2
// @RequestMapping(name = "/add/{a}/{b}", method = RequestMethod.DELETE)
// value 换成 name。不行。
@RequestMapping(value = "/add/{a}/{b}", method = RequestMethod.DELETE)
// == @DeleteMapping("/add/{a}/{b}")
public String test01(@PathVariable int a, @PathVariable int b, Model model) {
System.out.println("a = " + a);
System.out.println("b = " + b);
// 名字必须一致。a 和 b 顺序可以不同。
// @RequestMapping("/add/{b}/{a}")
// http://localhost:8080/03/add/1/2
// a = 2, b = 1
// int 可以改为 String。
int res = a + b;
model.addAttribute("msg", "结果为 " + res);
return "test";
}
}
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package org.springframework.web.bind.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.core.annotation.AliasFor;
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
public @interface RequestMapping {
String name() default "";
@AliasFor("path")
String[] value() default {};
@AliasFor("value")
String[] path() default {};
RequestMethod[] method() default {};
String[] params() default {};
String[] headers() default {};
String[] consumes() default {};
String[] produces() default {};
}
package com.geek.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
@Controller
public class RESTfulController {
@GetMapping("/add/{a}/{b}")
public String test02(@PathVariable int a, @PathVariable int b, Model model) {
System.out.println("a = " + a);
System.out.println("b = " + b);
int res = a + b;
model.addAttribute("msg", "结果 1 为 " + res);
return "test";
}
/*
<form action="/03/add/1/3" method="post">
<input type="submit">
</form>
*/
@PostMapping("/add/{a}/{b}")
public String test03(@PathVariable int a, @PathVariable int b, Model model) {
System.out.println("a = " + a);
System.out.println("b = " + b);
int res = a + b;
model.addAttribute("msg", "结果 2 为 " + res);
return "test";
}
// http://localhost:8080/03/add?a=1&b=2
@RequestMapping(value = "/add")
public String test00(int a, int b, Model model) {
System.out.println("a = " + a);
System.out.println("b = " + b);
// 名字必须一致。a 和 b 顺序可以不同。
// http://localhost:8080/03/add?b=2&a=1
int res = a + b;
model.addAttribute("msg", "结果为 " + res);
return "test";
}
}
RESTFul 好处。
http://localhost:8080/add?a=1&b=2
http://localhost:8080/add/1/2
- 简洁。
- 高效:支持缓存。
- 安全。
重定向和转发。
ModelAndView。
设置 ModelAndView 对象,根据 view 的名称,和视图解析器跳转到指定的页面。
页面:{视图解析器前缀}- viewName +{视图解析器后缀}
<!-- 视图解析器。以后:模板引擎:Thymeleaf,Freemarker。。。-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
对应的 controller 类。
package com.geek.controller;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
// 实现 Controller 接口的类可以获得控制器的功能。
// <url-pattern>/</url-pattern>
public class ControllerTest01 implements Controller {
@Override
public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("msg", "ControllerTest01");
modelAndView.setViewName("test");
return modelAndView;
}
}
Servlet API。
通过 Servlet API,不需要视图解析器。
通过 HttpServletResponse 进行输出。
通过 HttpServletResponse 实现重定向。
通过 HttpServletResponse 转发。
而 SpringMVC 则封装了,查看 doService(req, resp);。
package com.geek.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Controller
public class ResultGo {
@RequestMapping("/result/t1")
public void test01(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws IOException {
// 通过 HttpServletResponse 进行输出。
httpServletResponse.getWriter().println("hello, Spring By Servlet API");
}
@RequestMapping("/result/t2")
public void test02(HttpServletRequest request, HttpServletResponse response) throws IOException {
// 通过 HttpServletResponse 实现重定向。
response.sendRedirect("/index.jsp");
}
@RequestMapping("/result/t3")
public void test03(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {
// 通过 HttpServletResponse 转发。
req.setAttribute("msg", "/result/t3");
req.getRequestDispatcher("/WEN-INF/jsp/test.jsp").forward(req, resp);
}
}
package com.geek.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
@Controller
public class ModelTest01 {
@RequestMapping("/m1/t1")
public String test01(HttpServletRequest request, HttpServletResponse response) {
HttpSession session = request.getSession();
System.out.println(session.getId());
// 7BC03EFC20B0326BDA5682F0409444B0
return "test";
}
}
SpringMVC。
转发&重定向。
通过 SpringMVC 实现转发和重定向 ~ 无需视图解析器。
return “/index.jsp”;// 转发。
return “forword:/index.jsp”;// 转发。
return “redirect:/index.jsp”;// 重定向。
package com.geek.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
@Controller
public class ModelTest01 {
@RequestMapping("/m1/t1")
public String test01(HttpServletRequest request, HttpServletResponse response) {
HttpSession session = request.getSession();
System.out.println(session.getId());
// 7BC03EFC20B0326BDA5682F0409444B0
return "test";
}
// 没有配视图解析器。转发。全路径。
@RequestMapping("/m1/t2")
public String test02(Model model) {
// 转发。url 不变。
// http://localhost:8080/03/m1/t2
model.addAttribute("msg", "ModelTest01");
// return "/WEB-INF/jsp/test.jsp";// forward:(可以不写)。
return "forward:/WEB-INF/jsp/test.jsp";// forward:
}
// 没有配视图解析器。重定向。
@RequestMapping("/m1/t3")
public String test03(Model model) {
// 重定向。url 改变。
// http://localhost:8080/03/m1/t3
// http://localhost:8080/03/index.jsp?msg=ModelTest01
model.addAttribute("msg", "ModelTest01");
// return "/WEB-INF/jsp/test.jsp";// WEB-INF 下的 jsp 不能重定向访问。
return "redirect:/index.jsp";
}
// 配置了视图解析器。重定向。
@RequestMapping("/m1/t4")
public String test04(Model model) {
// 重定向。
// http://localhost:8080/03/m1/t4
// http://localhost:8080/03/index.jsp?msg=ModelTest01
model.addAttribute("msg", "ModelTest01");
return "redirect:/index.jsp";
// return "redirect1:/index.jsp";
// /03/WEB-INF/jsp/redirect1:/index.jsp.jsp
}
// 配置了视图解析器。转发。
@RequestMapping("/m1/t5")
public String test05(Model model) {
// 转发。地址不变。
// http://localhost:8080/03/m1/t5
model.addAttribute("msg", "ModelTest01");
return "test";
}
}
接受请求参数及数据回显。
https://mp.weixin.qq.com/s/1d_PAk2IIp-WWX2eBbU3aw
处理提交的数据。
提交的域名称和处理方法的参数名一致。
http://localhost:8080/hello?name=geek
package com.geek.controller;
import com.geek.pojo.User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
@Controller
@RequestMapping("/user")
public class UserController {
// http://localhost:8080/user/t1?name=geek
@GetMapping("/t1")
public String test01(@RequestParam("username") String name, Model model) {// @RequestParam 一律写上。表示是前端传递的参数。指定必须传递的参数,规范。
// 接收前端参数。
System.out.println("接收到前端的参数为:" + name);
// 将返回的结果传递给前端。model。
model.addAttribute("msg", name);
// 视图跳转。
return "test";
}
}
~
name = geek
http://localhost:8080/user/t1?username=geek
接收到前端的参数为:geek
提交的域名称和处理方法的参数名不一致。
http://localhost:8080/hello?name=geek
package com.geek.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
@Controller
public class DataController {
// 两个 @RequestMapping("/hello")
// org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping': Invocation of init method failed; nested exception is java.lang.IllegalStateException: Ambiguous mapping. Cannot map 'dataController' method
//public java.lang.String com.geek.controller.DataController.hello2(java.lang.String)
//to {[/hello]}: There is already 'dataController' bean method
//public java.lang.String com.geek.controller.DataController.hello1(java.lang.String) mapped.
// 不传参数或 "name" 不一样(?username),都为 null。
@RequestMapping("/hello1")
public String hello1(String name) {
System.out.println("name = " + name);
return "test";
}
// 不传参数或 "username" 不一样(?name),
// HTTP Status 400 – 错误的请求
//Type Status Report
//
//消息 Required String parameter 'name' is not present
//
//描述 由于被认为是客户端对错误(例如:畸形的请求语法、无效的请求信息帧或者虚拟的请求路由),服务器无法或不会处理当前请求。
//
//Apache Tomcat/8.5.53
// http://localhost:8080/03/hello2?name
// 或
// http://localhost:8080/03/hello2?name=
// 打印结果都为
// name =
// name =
@RequestMapping("/hello2")
public String hello2(@RequestParam String name) {
System.out.println("name = " + name);
return "test";
}
// 中间商。前端传入的 a
// 在 Java 中对应 name。
@RequestMapping("/hello3")
public String hello3(@RequestParam("a") String name) {
System.out.println("name = " + name);
return "test";
}
}
提交的是一个对象。
要求提交的表单和对象的属性名一致,参数使用对象即可。
package com.geek.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private int id;
private String name;
private int age;
}
package com.geek.controller;
import com.geek.pojo.User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
@Controller
@RequestMapping("/user")
public class UserController {
// 接收前端的一个对象。id,name,age。
@GetMapping("/t2")
public String test02(User user) {
System.out.println("user = " + user);
return "test";
}
// http://localhost:8080/user/t2?username=geek&id=1&age=3
// user = User(id=1, name=null, age=3)
// 对象匹配已传递的属性值。没有传递或名字不一样对象属性则使用默认值。
// http://localhost:8080/user/t2?username=geek&id=1&a=3
// user = User(id=1, name=null, age=0)
}
数据显示到前端。
ModelAndView。
package com.geek.controller;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
// 实现 Controller 接口的类可以获得控制器的功能。
// <url-pattern>/</url-pattern>
public class ControllerTest01 implements Controller {
@Override
public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("msg", "ControllerTest01");
modelAndView.setViewName("test");
return modelAndView;
}
}
Model。
package com.geek.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
@Controller
public class ReturnModel {
@RequestMapping("/ct2/hello")
public String hello(@RequestParam("username") String name, Model model) {
// 封闭要显示到视图中的数据。
// 相当于 req.setAttribute("name", name);
model.addAttribute("msg", name);
System.out.println(name);
return "test";
}
// http://localhost:8080/ct2/hello?username=geek
// geek
}
ModelMap。
Model 只有寥寥几个方法只适合用于储存数据,简化了新手对于 Model 对象的操作和理解。
ModelMap 继承了 LinkedMap,除了实现了自身的一些方法,同样的继承 LinkedMap 的方法和特性。
ModelAndView 可以在储存数据的同时,可以进行设置返回的逻辑视图,进行控制展示层的跳转。
@RequestMapping("/hello")
public String hello(@RequestParam("username") String name, ModelMap model) {
// 封装要显示到视图中的数据。
// 相当于 req.setAttribute("name", name);
model.addAttribute("name", name);
System.out.println(name);
return "hello";
}
乱码。
post 传数据,乱码。
<%--
Created by IntelliJ IDEA.
User: geek
Date: 2020-04-22
Time: 13:13:40
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<form action="/e/t1" method="post">
<input type="text" name="name">
<input type="submit">
</form>
</body>
</html>
package com.geek.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PostMapping;
@Controller
public class EncodingController {
@PostMapping("/e/t1")
public String test1(String name, Model model) {
System.out.println("name = " + name);
// name = ???
model.addAttribute("msg", name);
return "test";
}
}
解决。过滤器。
package com.geek.filter;
import org.springframework.stereotype.Controller;
import javax.servlet.*;
import java.io.IOException;
@Controller
public class EncodingFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println(servletRequest.getCharacterEncoding());
servletRequest.setCharacterEncoding("utf-8");
servletResponse.setCharacterEncoding("utf-8");
filterChain.doFilter(servletRequest, servletResponse);
}
@Override
public void destroy() {
}
}
- 配置。web.xml。
<filter>
<filter-name>encoding</filter-name>
<filter-class>com.geek.filter.EncodingFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>encoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
// 注意必须为 /*
。
/* ——> 匹配所有请求。(包括 .jsp)。
SpringMVC 提供了 Encoding Filter。
<!-- SpringMVC 提供的乱码过滤器。-->
<filter>
<filter-name>encoding</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>encoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Json
https://mp.weixin.qq.com/s/RAqRKZJqsJ78HRrJg71R1g
JSON(JavaScript Object Notation, JS 对象简谱) 是一种轻量级的数据交换格式。它基于 ECMAScript (欧洲计算机协会制定的js规范)的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据。简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。 易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率。
- 百科。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script type="text/javascript">
// <!-- JavaScrypt。-->
var user = {
name: "geek",
age: 3,
sex: "男"
};
console.log(user)
// 将 js 对象转换为 json 对象。
var json = JSON.stringify(user);
console.log(json);
console.log("~ ~ ~ ~ ~ ~ ~");
// 将 json 对象转换为 JavaScript 对象。
var parse = JSON.parse(json);
console.log(parse);
</script>
<!-- script 永远不能单闭合。-->
</head>
<body>
</body>
</html>
Java 生成 Json 对象 ~ jackson。
jackson。
阿里巴巴的 fastjson。。。。
pom 中加入 jackson 依赖。
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.10.2</version>
</dependency>
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">
<!-- 注册 DispatcherServlet。-->
<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-context.xml</param-value>
</init-param>
<!-- 启动顺序。数字越小,启动越早。-->
<load-on-startup>1</load-on-startup>
</servlet>
<!-- 所有请求都会被 SpringMVC 拦截。-->
<servlet-mapping>
<servlet-name>SpringMVC</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
<filter>
<filter-name>encoding</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>encoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
package com.geek.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private String name;
private int age;
private String sex;
}
-
controller。(返回字符串)。
@ResponseBody// 不走视图解析器,直接返回一个字符串。
package com.geek.controller;
import com.geek.pojo.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class UserController {
@RequestMapping("/j1")
@ResponseBody// 不走视图解析器,直接返回一个字符串。
public String json01() {
// 创建一个对象。
User user = new User("Geek1", 3, "男");
return user.toString();
// User(name=Geek1, age=3, sex=?)
}
}
- controller。(返回 Json 对象)。
package com.geek.controller;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.geek.pojo.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class UserController {
@RequestMapping("/j1")
@ResponseBody
public String json01() throws JsonProcessingException {
// jackson。ObjectMapper。
ObjectMapper objectMapper = new ObjectMapper();
User user = new User("Geek01", 3, "男");
String json = objectMapper.writeValueAsString(user);// 把 value(User)变成 String。
return json;
// {"name":"Geek01","age":3,"sex":"?"}
}
}
json 乱码。
@RequestMapping(value = "/j1", produces = "application/json; charset=UTF-8")// json 乱码问题。
@RequestMapping("/j1")
@ResponseBody
public String json01() throws JsonProcessingException {
SpringMVC 解决 json 乱码。
<!-- Json 乱码问题配置。-->
<mvc:annotation-driven>
<mvc:message-converters register-defaults="true">
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<constructor-arg value="UTF-8"/>
</bean>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="objectMapper">
<bean class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean">
<property name="failOnEmptyBeans" value="false"/>
</bean>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
package com.geek.controller;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.geek.pojo.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class UserController {
// @RequestMapping(value = "/j0", produces = "application/json; charset=UTF-8")// json 乱码问题。
@RequestMapping(value = "/j0")// json 乱码问题通过 springmvc-context.xml 解决。
@ResponseBody// 不走视图解析器,直接返回一个字符串。
public String json00() {
// 创建一个对象。
User user = new User("Geek1", 3, "男");
System.out.println("user = " + user);
return user.toString();
// User(name=Geek1, age=3, sex=?)
// User(name=Geek1, age=3, sex=男)
}
// @RequestMapping(value = "/j1", produces = "application/json; charset=UTF-8")// json 乱码问题。
@RequestMapping(value = "/j1")// json 乱码问题通过 springmvc-context.xml 解决。
@ResponseBody
public String json01() throws JsonProcessingException {
// jackson。ObjectMapper。
ObjectMapper objectMapper = new ObjectMapper();
User user = new User("Geek01", 3, "男");
String json = objectMapper.writeValueAsString(user);// 把 value(User)变成 String。
return json;
// {"name":"Geek01","age":3,"sex":"?"}
// {"name":"Geek01","age":3,"sex":"男"}
}
}
@RestController。
前后端分离时,一般就用 @RestController。只返回 Json 数据给前端。
@RestController = @Controller + @ResponseBody。
//@Controller
@RestController// 返回 Json 字符串。(返回字符串)。// 方法上就可以不用 @ResponseBody 了。
public class UserController {
// @RequestMapping(value = "/j0", produces = "application/json; charset=UTF-8")// json 乱码问题。
@RequestMapping(value = "/j0")// json 乱码问题通过 springmvc-context.xml 解决。
// @ResponseBody// 不走视图解析器,直接返回一个字符串。
public String json00() {
package com.geek.controller;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.geek.pojo.User;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
//@Controller
@RestController// 返回 Json 字符串。(返回字符串)。// 方法上就可以不用 @ResponseBody 了。
//@RestController = @Controller + @ResponseBody。
public class UserController {
// @RequestMapping(value = "/j0", produces = "application/json; charset=UTF-8")// json 乱码问题。
@RequestMapping(value = "/j0")// json 乱码问题通过 springmvc-context.xml 解决。
// @ResponseBody// 不走视图解析器,直接返回一个字符串。
public String json00() {
// 创建一个对象。
User user = new User("Geek1", 3, "男");
System.out.println("user = " + user);
return user.toString();
// User(name=Geek1, age=3, sex=?)
// User(name=Geek1, age=3, sex=男)
}
// @RequestMapping(value = "/j1", produces = "application/json; charset=UTF-8")// json 乱码问题。
@RequestMapping(value = "/j1")// json 乱码问题通过 springmvc-context.xml 解决。
// @ResponseBody
public String json01() throws JsonProcessingException {
// jackson。ObjectMapper。
ObjectMapper objectMapper = new ObjectMapper();
User user = new User("Geek01", 3, "男");
String json = objectMapper.writeValueAsString(user);// 把 value(User)变成 String。
return json;
// {"name":"Geek01","age":3,"sex":"?"}
// {"name":"Geek01","age":3,"sex":"男"}
}
@RequestMapping("/j2")
public String json02() throws JsonProcessingException {
ObjectMapper objectMapper = new ObjectMapper();
List<User> userList = new ArrayList<>();
User user = new User("李1", 3, "男");
User user1 = new User("李2", 3, "男");
User user2 = new User("李3", 3, "男");
User user3 = new User("李4", 3, "男");
userList.add(user);
userList.add(user1);
userList.add(user2);
userList.add(user3);
String asString = objectMapper.writeValueAsString(userList);
return asString;
// [{"name":"李1","age":3,"sex":"男"},{"name":"李2","age":3,"sex":"男"},{"name":"李3","age":3,"sex":"男"},{"name":"李4","age":3,"sex":"男"}]
}
@RequestMapping("/j3")
public String json03() throws JsonProcessingException {
Date date = new Date();
return new ObjectMapper().writeValueAsString(date);
// 1587545448892
}
}
- SimpleDateFormat。
@RequestMapping("/j3")
public String json03() throws JsonProcessingException {
Date date = new Date();
// 自定义日期格式。
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-mm-dd HH:mm:ss");
return new ObjectMapper().writeValueAsString(simpleDateFormat.format(date));
// 1587545448892
}
@RequestMapping("/j3")
public String json03() throws JsonProcessingException {
ObjectMapper objectMapper = new ObjectMapper();
// 使用 objectMapper,关闭默认的时间戳格式化。
objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
// 自定义日期格式。
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-mm-dd HH:mm:ss");
objectMapper.setDateFormat(simpleDateFormat);
Date date = new Date();
return objectMapper.writeValueAsString(date);
}
- 工具类封装简化。
package com.geek.util;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import java.text.SimpleDateFormat;
public class JsonUtils {
public static String getJson(Object object, String dateFormat) {
ObjectMapper objectMapper = new ObjectMapper();
// 使用 objectMapper,关闭默认的时间戳格式化。
objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
// 自定义日期格式。
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(dateFormat);
objectMapper.setDateFormat(simpleDateFormat);
try {
return objectMapper.writeValueAsString(object);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return null;
}
}
//@Controller
@RestController// 返回 Json 字符串。(返回字符串)。// 方法上就可以不用 @ResponseBody 了。
//@RestController = @Controller + @ResponseBody。
public class UserController {
@RequestMapping("/j4")
public String json04() {
Date date = new Date();
return JsonUtils.getJson(date, "yyyy-MM-dd HH:mm:ss");
}
}
工具类代码复用问题。
package com.geek.util;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import java.text.SimpleDateFormat;
public class JsonUtils {
public static String getJson(Object object) {
return getJson(object, "yyyy-mm-dd HH:mm:ss");// 工具类代码复用。
}
public static String getJson(Object object, String dateFormat) {
ObjectMapper objectMapper = new ObjectMapper();
// 使用 objectMapper,关闭默认的时间戳格式化。
objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
// 自定义日期格式。
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(dateFormat);
objectMapper.setDateFormat(simpleDateFormat);
try {
return objectMapper.writeValueAsString(object);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return null;
}
}
@RestController 就是把一个对象
转为字符串
直接返回到前台页面。
FastJson。
fastjson 是阿里巴巴的开源 JSON 解析库,它可以解析 JSON 格式的字符串,支持将 Java Bean 序列化为 JSON 字符串,也可以从 JSON 字符串反序列化到 JavaBean。
<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.67</version>
</dependency>
package com.geek.controller;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.geek.pojo.User;
import com.geek.util.JsonUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
//@Controller
@RestController// 返回 Json 字符串。(返回字符串)。// 方法上就可以不用 @ResponseBody 了。
//@RestController = @Controller + @ResponseBody。
public class UserController {
@RequestMapping("/j5")
public String json05() {
List<User> userList = new ArrayList<>();
User user = new User("李1", 3, "男");
User user1 = new User("李2", 3, "男");
User user2 = new User("李3", 3, "男");
User user3 = new User("李4", 3, "男");
userList.add(user);
userList.add(user1);
userList.add(user2);
userList.add(user3);
System.out.println("~ ~ ~ ~ ~ ~ ~ Java 对象 转 JSON 字符串~ ~ ~ ~ ~ ~ ~ ");
String str1 = JSON.toJSONString(userList);
System.out.println("JSON.toJSONString(userList) ==> " + str1);
String str2 = JSON.toJSONString(user1);
System.out.println("JSON.toJSONString(user1) ==> " + str2);
System.out.println("\n~ ~ ~ ~ ~ ~ ~ JSON 字符串 转 Java 对象~ ~ ~ ~ ~ ~ ~ ");
User jp_user1 = JSON.parseObject(str2, User.class);
System.out.println("JSON.parseObject(str2,User.class) ==> " + jp_user1);
System.out.println("\n~ ~ ~ ~ ~ ~ ~ Java 对象 转 JSON 对象~ ~ ~ ~ ~ ~ ~ ");
JSONObject jsonObject1 = (JSONObject) JSON.toJSON(user2);
System.out.println("(JSONObject) JSON.toJSON(user2) ==> " + jsonObject1.getString("name"));
System.out.println("\n~ ~ ~ ~ ~ ~ ~ JSON 对象 转 Java 对象~ ~ ~ ~ ~ ~ ~ ");
User to_java_user = JSON.toJavaObject(jsonObject1, User.class);
System.out.println("JSON.toJavaObject(jsonObject1, User.class) ==> " + to_java_user);
return "hello";
}
}
ssm 整合。
https://mp.weixin.qq.com/s/SDxqGu_il3MUCTcN1EYrng
数据库准备。
CREATE SCHEMA `ssmbuild` DEFAULT CHARACTER SET utf8 ;
use ssmbuild;
CREATE TABLE `ssmbuild`.`books` (
`bookID` INT NOT NULL AUTO_INCREMENT COMMENT '书 id。',
`bookName` VARCHAR(45) NOT NULL COMMENT '书名。',
`bookCounts` INT(11) NOT NULL COMMENT '数量。',
`detail` VARCHAR(200) NOT NULL COMMENT '描述。',
KEY `bookId` (`bookID`)
) ENGINE=INNODB DEFAULT CHARACTER SET=UTF8;
INSERT INTO `ssmbuild`.`books` (`bookName`, `bookCounts`, `detail`) VALUES ('Java', '1', '从入门到放弃。');
INSERT INTO `ssmbuild`.`books` (`bookName`, `bookCounts`, `detail`) VALUES ('MySQL', '10', '从删库到跑路。');
INSERT INTO `ssmbuild`.`books` (`bookName`, `bookCounts`, `detail`) VALUES ('Linux', '5', '从进门到进牢。');
- pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.geek</groupId>
<artifactId>ssmbuild</artifactId>
<version>1.0-SNAPSHOT</version>
<!-- 依赖。-->
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.19</version>
</dependency>
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.3</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.2</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!-- MyBatis。-->
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.3</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
</dependencies>
<!-- 静态资源导出问题。-->
</project>
IDEA 集成数据库连接。
右侧点击 Database 选项卡。+
号。
Bootstrap 可视化布局。
Ajax。
https://mp.weixin.qq.com/s/tB4YX4H59wYS6rxaO3K2_g
Ajax 即 “Asynchronous Javascript And XML”(异步 JavaScript 和 XML),是指一种创建交互式、快速动态网页应用的网页开发技术,无需重新加载整个网页的情况下,能够更新部分网页的技术。
通过在后台与服务器进行少量数据交换,Ajax 可以使网页实现异步更新。这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新。
Ajax 不是一种新的编程语言,而是一种用于创建更好更快以及交互性更强的 Web 应用程序的技术。
2005 年,Google 通过其 Google Suggest 使 AJAX 变得流行起来。Google Suggest 能够自动帮你完成搜索单词。
Google Suggest 使用 AJAX 创造出动态性极强的 web 界面:当您在谷歌的搜索框输入关键字时,JavaScript 会把这些字符发送到服务器,然后服务器会返回一个搜索建议的列表。
就和国内百度的搜索框一样!
传统的网页(即不用 ajax 技术的网页),想要更新内容或者提交一个表单,都需要重新加载整个网页。
使用 ajax 技术的网页,通过在后台服务器进行少量的数据交换,就可以实现异步局部更新。
使用 Ajax,用户可以创建接近本地桌面应用的直接、高可用、更丰富、更动态的Web用户界面。
-
纯 js 原生 Ajax ~ XMLHttpRequest。
-
jQuery Ajax。
jQuery 的一个库,js 大量函数(方法)。
代码。
<?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">
<!-- 自动扫描指定的包。包下所有有注解的类交给 Spring IoC 容器管理。-->
<context:component-scan base-package="com.geek.controller"/>
<!-- 静态资源过滤。-->
<mvc:default-servlet-handler/>
<mvc:annotation-driven/>
<!-- 视图解析器。-->
<bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 前缀。-->
<property name="prefix" value="/WEB-INF/jsp/"/>
<!-- 后缀。-->
<property name="suffix" value=".jsp"/>
</bean>
</beans>
- 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:applicationContext.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>
<filter>
<filter-name>encoding</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>encoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
jQuery.each(["get", "post"], function (_i, method) {
jQuery[method] = function (url, data, callback, type) {
// Shift arguments if data argument was omitted
if (isFunction(data)) {
type = type || callback;
callback = data;
data = undefined;
}
// The url can be an options object (which then must have .url)
return jQuery.ajax(jQuery.extend({
url: url,
type: method,
dataType: type,
data: data,
success: callback
}, jQuery.isPlainObject(url) && url));
};
});
- controller。
package com.geek.controller;
import com.geek.pojo.User;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
@RestController// 自动返回字符串。
public class AjaxController {
@RequestMapping("/a2")
public List<User> a2() {
List<User> userList = new ArrayList<>();
// 添加数据。
userList.add(new User("geek_Java", 1, "男"));
userList.add(new User("geek_前端", 1, "男"));
userList.add(new User("geek_运维", 1, "男"));
return userList;
}
}
以前我们直接请求 localhost:8080/a2。
就会跳转页面并显示 Json 字符串。
[{“name”:“geek_Java”,“age”:1,“sex”:“男”},{“name”:“geek_前端”,“age”:1,“sex”:“男”},{“name”:“geek_运维”,“age”:1,“sex”:“男”}]
使用 Ajax 就不会跳转页面。
Ajax 请求数据并异步展示。
<%--
Created by IntelliJ IDEA.
User: geek
Date: 2020-04-27
Time: 22:30:22
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
<script src="${pageContext.request.contextPath}/statics/js/jquery-3.5.0.js"></script>
<script>
$(function () {
$("#btn").click(function () {
// console.log("111")
$.post("${pageContext.request.contextPath}/a2", function (data) {
// console.log(data)
var html = "";
for (let i = 0; i < data.length; i++) {
html += "<tr>" +
"<td>" + data[i].name + "</td>" +
"<td>" + data[i].age + "</td>" +
"<td>" + data[i].sex + "</td>" +
+"</tr>"
}
$("#content").html(html)
})
})
})
</script>
</head>
<body>
<input type="button" value="加载数据" id="btn">
<table>
<tr>
<td>姓名</td>
<td>年龄</td>
<td>性别</td>
</tr>
<tbody id="content">
</tbody>
</table>
</body>
</html>
Ajax 验证用户名。
package com.geek.controller;
import com.geek.pojo.User;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
@RestController// 自动返回字符串。
public class AjaxController {
@RequestMapping("/a3")
public String a3(String name, String pwd) {
String msg = "";
if (name != null) {
if ("admin".equals(name)) {
msg = "ok";
} else {
msg = "用户名有误。";
}
}
if (pwd != null) {
if ("123".equals(name)) {
msg = "ok";
} else {
msg = "密码有误。";
}
}
return msg;
}
}
<%--
Created by IntelliJ IDEA.
User: geek
Date: 2020-04-27
Time: 22:56:48
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
<script src="${pageContext.request.contextPath}/statics/js/jquery-3.5.0.js"></script>
<script>
function a1() {
$.post({
url: "${pageContext.request.contextPath}/a3",
data: {"name": $("#name").val()},
success: function (data) {
if (data.toString() === 'ok') {
$("#userInfo").css("color", "green")
} else {
$("#userInfo").css("color", "red")
}
$("#userInfo").html(data);
}
})
}
function a2() {
$.post({
url: "${pageContext.request.contextPath}/a3",
data: {"pwd": $("#pwd").val()},
success: function (data) {
if (data.toString() === 'ok') {
$("#pwdInfo").css("color", "green")
} else {
$("#pwdInfo").css("color", "red")
}
$("#pwdInfo").html(data);
}
})
}
</script>
</head>
<body>
<p>
用户名:<input type="text" id="name" onblur="a1()">
<span id="userInfo"></span>
</p>
<p>
密 码:<input type="text" id="pwd" onblur="a2()">
<span id="pwdInfo"></span>
</p>
</body>
</html>
拦截器。
https://mp.weixin.qq.com/s/NWJoYiirbkSDz6x01Jji3g
SpringMVC 的处理器拦截器类似于 Servlet 开发中的过滤器 Filter,用于对处理器进行预处理和后处理。开发者可以自己定义一些拦截器来实现特定的功能。
过滤器与拦截器的区别:拦截器是 AOP 思想的具体应用。
- 过滤器。
servlet 规范中的一部分,任何 Java Web工程都可以使用。
在 url-pattern 中配置了 /* 之后,可以对所有要访问的资源进行拦截。
- 拦截器。
拦截器是 SpringMVC 框架自己的,只有使用了 SpringMVC 框架的工程才能使用。
拦截器只会拦截访问的控制器方法,如果访问的是 jsp / html / css / image / js 是不会进行拦截的。
Filter 必须重写方法。
package com.geek.config;
import javax.servlet.*;
import java.io.IOException;
public class MyFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
}
@Override
public void destroy() {
}
}
自定义拦截器。
想要自定义拦截器,必须实现 HandlerInterceptor 接口。
-
新建一个 Moudule,springmvc-06-Interceptor,添加 Web 支持。
-
编写一个拦截器。
package com.geek.config;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class MyInterceptor implements HandlerInterceptor {
// return true,就执行下一个拦截器,放行。
// return false,不执行下一个拦截器。
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("preHandle。。。");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("postHandle。。。");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion。。。");
}
}
- 配置 web.xml 和 springmvc-servlet.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:applicationContext.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>
<filter>
<filter-name>encoding</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>encoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
<?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">
<!-- 自动扫描指定的包。包下所有有注解的类交给 Spring IoC 容器管理。-->
<context:component-scan base-package="com.geek.controller"/>
<!-- 静态资源过滤。-->
<mvc:default-servlet-handler/>
<!-- Json 乱码问题配置。-->
<mvc:annotation-driven>
<mvc:message-converters register-defaults="true">
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<constructor-arg value="UTF-8"/>
</bean>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="objectMapper">
<bean class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean">
<property name="failOnEmptyBeans" value="false"/>
</bean>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
<!-- 视图解析器。-->
<bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 前缀。-->
<property name="prefix" value="/WEB-INF/jsp/"/>
<!-- 后缀。-->
<property name="suffix" value=".jsp"/>
</bean>
<!-- 拦截器。-->
<mvc:interceptors>
<mvc:interceptor>
<!-- 包括这个请求下面的所有请求。-->
<mvc:mapping path="/**"/>
<bean class="com.geek.config.MyInterceptor"/>
</mvc:interceptor>
<mvc:interceptor>
<mvc:mapping path="/user/**"/>
<bean class="com.geek.config.LoginInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
</beans>
登录判断验证。
/user 请求包含登录请求。拦截 /user 下的请求。
<?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">
<!-- 自动扫描指定的包。包下所有有注解的类交给 Spring IoC 容器管理。-->
<context:component-scan base-package="com.geek.controller"/>
<!-- 静态资源过滤。-->
<mvc:default-servlet-handler/>
<!-- Json 乱码问题配置。-->
<mvc:annotation-driven>
<mvc:message-converters register-defaults="true">
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<constructor-arg value="UTF-8"/>
</bean>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="objectMapper">
<bean class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean">
<property name="failOnEmptyBeans" value="false"/>
</bean>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
<!-- 视图解析器。-->
<bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 前缀。-->
<property name="prefix" value="/WEB-INF/jsp/"/>
<!-- 后缀。-->
<property name="suffix" value=".jsp"/>
</bean>
<!-- 拦截器。-->
<mvc:interceptors>
<mvc:interceptor>
<!-- 包括这个请求下面的所有请求。-->
<mvc:mapping path="/**"/>
<bean class="com.geek.config.MyInterceptor"/>
</mvc:interceptor>
<mvc:interceptor>
<mvc:mapping path="/user/**"/>
<bean class="com.geek.config.LoginInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
</beans>
package com.geek.config;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 没有登录,进入首页时跳转登录。
HttpSession session = request.getSession();
// 登录页面也放行。
if (request.getRequestURI().contains("goLogin")) {
return true;
}
// 第一次提交登录的请求也放行。
if (request.getRequestURI().contains("login")) {
return true;
}
// 登录过就放行。注意第一次登录是没有 session 的。
if (session.getAttribute("userLoginInfo") != null) {
return true;
}
// 判断什么情况下是没有登录。
request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request, response);
return false;
}
}
- 退出登录。
@RequestMapping("/goOut")
public String login(HttpSession session) {
// session.invalidate();// 浏览器关闭自动 invalidate()。
session.removeAttribute("userLoginInfo");
return "main";
}
文件上传下载。
pom.xml。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>SpringMVCGeek</artifactId>
<groupId>com.geek</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>springmvc-07-file</artifactId>
<dependencies>
<!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.3</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
</dependency>
</dependencies>
</project>
文件上传是开发中最常见的功能之一。SpringMVC 可以很好的支持文件上传,但是 SpringMVC 上下文中默认没有装配 MultipartResolver,因此默认情况下其不能处理文件上传工作。如果想使用 Spring 的文件上传功能,则需要在上下文中配置 MultipartResolver。
前端表单要求:为了能上传文件,必须将表单的 method 设置为 POST,并将 enctype 设置为 multipart/form-data。只有在这样的情况下,浏览器才会把用户选择的文件以二进制数据发送给服务器。
一旦设置了 enctype 为 multipart/form-data,浏览器即会采用二进制流的方式来处理表单数据,而对于文件上传的处理则涉及在服务器端解析原始的 HTTP 响应。在 2003 年,Apache Software Foundation 发布了开源的 Commons FileUpload 组件,其很快成为Servlet/JSP 程序员上传文件的最佳选择。
Servlet3.0 规范已经提供方法来处理文件上传,但这种上传需要在 Servlet 中完成。
而 SpringMVC 则提供了更简单的封装。
SpringMVC为 文件上传提供了直接的支持,这种支持是用即插即用的 MultipartResolver 实现的。
SpringMVC 使用 Apache Commons FileUpload 技术实现了一个 MultipartResolver 实现类:CommonsMultipartResolver。因此,SpringMVC 的文件上传还需要依赖 Apache Commons FileUpload 的组件。
HTML 标签的 enctype 属性。
https://www.w3school.com.cn/tags/att_form_enctype.asp
-
application/x-www-form-urlencoded
在发送前编码所有字符(默认) -
multipart/form-data
不对字符编码。
在使用包含文件上传控件的表单时,必须使用该值。 -
text/plain
空格转换为 “+” 加号,但不对特殊字符编码。
适用直接通过表单发送邮件。
配置。
<?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">
<!-- 自动扫描指定的包。包下所有有注解的类交给 Spring IoC 容器管理。-->
<context:component-scan base-package="com.geek.controller"/>
<!-- 静态资源过滤。-->
<mvc:default-servlet-handler/>
<!-- Json 乱码问题配置。-->
<mvc:annotation-driven>
<mvc:message-converters register-defaults="true">
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<constructor-arg value="UTF-8"/>
</bean>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="objectMapper">
<bean class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean">
<property name="failOnEmptyBeans" value="false"/>
</bean>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
<!-- 视图解析器。-->
<bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 前缀。-->
<property name="prefix" value="/WEB-INF/jsp/"/>
<!-- 后缀。-->
<property name="suffix" value=".jsp"/>
</bean>
<!-- 文件上传的配置。id 必须为 multipartResolver。-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 请求的编码格式。必须和 jsp 的 pageEncoding 一致。以便正确读取表单的内容。默认为 ISO-8859-1。-->
<!--Default is ISO-8859-1, according to the Servlet spec.-->
<property name="defaultEncoding" value="utf-8"/>
<property name="maxInMemorySize" value="40960"/>
<!-- 上传文件的大小上限,单位为字节。10485760 = 10M。-->
<property name="maxUploadSize" value="10485760"/>
</bean>
</beans>
package com.geek.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.commons.CommonsMultipartFile;
import javax.servlet.http.HttpServletRequest;
import java.io.*;
@RestController
public class FileController {
// @RequestParam("file") 将 name = file 控件得到的文件封装成 CommonsMultipartFile 对象。
// 批量上传 CommonsMultipartFile 数组即可。
@RequestMapping("/upload")
public String fileUpload(@RequestParam("file") CommonsMultipartFile commonsMultipartFile,
HttpServletRequest request) throws IOException {
// 获取文件名。
String originalFilename = commonsMultipartFile.getOriginalFilename();
// 如果文件名为空,直接回到首页。
if ("".equals(originalFilename)) {
return "redirect:/index.jsp";
}
System.out.println("上传的文件名:" + originalFilename);
// 设置上传文件保存路径。
String path = request.getServletContext().getRealPath("/upload");
// 如果路径不存在,创建一个。
File realPath = new File(path);
if (!realPath.exists()) {
realPath.mkdir();
}
System.out.println("上传文件的保存地址:" + realPath);
InputStream inputStream = commonsMultipartFile.getInputStream();// 文件输入流。
OutputStream outputStream = new FileOutputStream(new File(realPath, originalFilename));
int validLen = 0;
byte[] bytes = new byte[1024];
while ((validLen = inputStream.read(bytes)) != -1) {
outputStream.write(bytes, 0, validLen);
outputStream.flush();
}
outputStream.close();
inputStream.close();
return "redirect:/index.jsp";
}
}
- 文件上传 Controller。
package com.geek.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.commons.CommonsMultipartFile;
import javax.servlet.http.HttpServletRequest;
import java.io.*;
@RestController
public class FileController {
public static void main(String[] args) {
System.out.println(File.pathSeparator);// ;
System.out.println(File.pathSeparatorChar);// ;
System.out.println(File.separator);// /
System.out.println(File.separatorChar);// /
}
@RequestMapping("/upload2")
public String fileUpload02(@RequestParam("file") CommonsMultipartFile commonsMultipartFile,
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 的方法直接写文件。
commonsMultipartFile.transferTo(new File(realPath + File.separator + commonsMultipartFile.getOriginalFilename()));
return "redirect:/index.jsp";
}
// @RequestParam("file") 将 name = file 控件得到的文件封装成 CommonsMultipartFile 对象。
// 批量上传 CommonsMultipartFile 数组即可。
@RequestMapping("/upload")
public String fileUpload(@RequestParam("file") CommonsMultipartFile commonsMultipartFile,
HttpServletRequest request) throws IOException {
// 获取文件名。
String originalFilename = commonsMultipartFile.getOriginalFilename();
// 如果文件名为空,直接回到首页。
if ("".equals(originalFilename)) {
return "redirect:/index.jsp";
}
System.out.println("上传的文件名:" + originalFilename);
// 设置上传文件保存路径。
String path = request.getServletContext().getRealPath("/upload");
// 如果路径不存在,创建一个。
File realPath = new File(path);
if (!realPath.exists()) {
realPath.mkdir();
}
System.out.println("上传文件的保存地址:" + realPath);
InputStream inputStream = commonsMultipartFile.getInputStream();// 文件输入流。
OutputStream outputStream = new FileOutputStream(new File(realPath, originalFilename));
int validLen = 0;
byte[] bytes = new byte[1024];
while ((validLen = inputStream.read(bytes)) != -1) {
outputStream.write(bytes, 0, validLen);
outputStream.flush();
}
outputStream.close();
inputStream.close();
return "redirect:/index.jsp";
}
}
- 下载。
package com.geek.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.commons.CommonsMultipartFile;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
@RestController
public class FileController {
public static void main(String[] args) {
System.out.println(File.pathSeparator);// ;
System.out.println(File.pathSeparatorChar);// ;
System.out.println(File.separator);// /
System.out.println(File.separatorChar);// /
}
@RequestMapping("/download")
public String download(HttpServletResponse response, HttpServletRequest request) throws IOException {
// 要下载的图片地址。
String path = request.getServletContext().getRealPath("/upload");
String fileName = "电脑配置信息 – 电脑管家检测结果.txt";
// 设置 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);
// 读取文件。输入流。
FileInputStream fileInputStream = new FileInputStream(file);
// 写出文件。输出流。
ServletOutputStream outputStream = response.getOutputStream();
byte[] bytes = new byte[1024];
int index = 0;
while ((index = fileInputStream.read(bytes)) != -1) {
outputStream.write(bytes, 0, index);
outputStream.flush();
}
outputStream.close();
fileInputStream.close();
return "ok";
}
}