初识SSM框架-SpringMVC

Spring MVC 是 Spring 提供的一个基于 MVC 设计模式的轻量级 Web 开发框架,本质上相当于 Servlet,属于SpringFrameWork的后续产品。Spring MVC 本身就是 Spring 框架的一部分,与 Spring 框架是无缝集成的。

MVC架构

MVC模式(Model–view–controller)是软件工程中的一种软件架构模式,把软件系统分为三个基本部分:模型(Model)、视图(View)和控制器(Controller)。

MVC模式的目的是实现一种动态的程序设计,使后续对程序的修改和扩展简化,并且使程序某一部分的重复利用成为可能。除此之外,此模式透过对复杂度的简化,使程序结构更加直观。软件系统透过对自身基本部分分离的同时也赋予了各个基本部分应有的功能。

  • 模型(Model) - 程序员编写程序应有的功能(实现算法等等)、数据库专家进行数据管理和数据库设计(可以实现具体的功能)。
  • 视图(View) - 界面设计人员进行图形界面设计。
  • 控制器(Controller)- 负责转发请求,对请求进行处理。

1.Model1

1.Modedl1主要分为两层,视图层和模型层。

2.JSP职责不单一,职责过重,不便于维护

2.Model2

1.用户发送请求->Servlet接受请求数据并调用对应的业务逻辑方法->业务处理完成后返回给更新后的数据给Servlet->Servlet转向到JSP,由JSP渲染页面->响应给前端更新后的页面

2.Controller

  • 取得表单数据
  • 调用事务逻辑
  • 转向指定的页面

3.Model

  • 业务逻辑
  • 保存数据状态

4.View

  • 显示页面

Servlet回顾

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
<!--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.ling</groupId>
<artifactId>SpringMVC</artifactId>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>
<modules>
<module>SpringMVC-01-Servlet</module>
<module>SpringMVC-02-Hello</module>
</modules>

<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>

<!--导入依赖 Tomcat9-->
<dependencies>
<!-- https://mvnrepository.com/artifact/junit/junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.13</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>

📣 使用Tomca9是一种明智的选择,Spring Framework尚未做到与Tomcat10 jakarta命名空间更改兼容,Tomcat10目前不能用于Spring框架(包括SpringBoot)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<!--导入依赖 Tomcat10-->
<dependencies>
<!-- https://mvnrepository.com/artifact/jakarta.servlet/jakarta.servlet-api -->
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
<version>5.0.0</version>
<scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/jakarta.servlet.jsp/jakarta.servlet.jsp-api -->
<dependency>
<groupId>jakarta.servlet.jsp</groupId>
<artifactId>jakarta.servlet.jsp-api</artifactId>
<version>3.0.0</version>
<scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.glassfish.web/jakarta.servlet.jsp.jstl -->
<dependency>
<groupId>org.glassfish.web</groupId>
<artifactId>jakarta.servlet.jsp.jstl</artifactId>
<version>2.0.0</version>
</dependency>
</dependencies>

👉 对于Spring MVC 5,Spring MVC DispatcherServlet 依赖于 javax.servlet.* 包命名空间(使用 Java EE 8 javax 包),而 Tomcat10 基于 Jakarta EE 9。(Tomcat10将所有包从javax.servlet重命名为 jakarta.servlet,目前 Spring Boot 和 Spring Framework 都不支持 Jakarta EE 9,可能在 Spring Framework 6 和 Spring Boot 3 对Tomcat10提供支持)

❓ 参考:Support for Jakarta EE 9


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class HelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
/*1.获取前端页面*/
String method = req.getParameter("method");
if(method.equals("add")){
req.getSession().setAttribute("msg","The add method was executed");
}
else if(method.equals("delete")){
req.getSession().setAttribute("msg","The delete method was executed");
}
req.getRequestDispatcher("/WEB-INF/jsp/test.jsp").forward(req,resp);
}

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
<%--form.jsp--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<form action="/hello" method="post">
<input type="text" name="method">
<input type="submit">
</form>
</body>
</html>
1
2
3
4
5
6
7
8
9
10
<%-- test.jsp --%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
${msg}
</body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!-- web.xml-->
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd"
version="5.0">
<servlet>
<servlet-name>Hello</servlet-name>
<servlet-class>com.ling.servlet.HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Hello</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
</web-app>

1.MVC框架:

  • 将url映射到java类或java类的方法
  • 封装用户提交的数据
  • 处理请求->调用相关的业务请求->封装响应数据
  • 将响应的数据用jsp/html进行渲染

2.常见的服务器端MVC框架有:Struts、Spring MVC、ASP.NET MVC、Zend Framework、JSF

3.常见前端MVC框架:Angular、React、Backbone、Vue


SpringMVC

Docs

SpringMVC:

  • 轻量级,简单易学
  • 高效,基于请求响应的MVC框架
  • 与Spring无缝集成
  • 约定大于配置
  • 职责分离清晰
  • 强大的适配能力、非侵入性和灵活性
  • 可定制的数据绑定和验证、处理器映射和视图解析
  • 灵活的模型传递

Spring MVC 框架是围绕 DispatcherServlet(继承 HttpServlet 基类) 来设计的,这个 Servlet 会把请求分发给各个处理器,并支持可配置的处理器映射、视图渲染、本地化、时区与主题渲染和文件上传等功能(以请求为驱动,围绕一个中心Servlet分派请求及提供其他功能)。


SpringMVC流程

1.🔧DispatcherServlet表示前置控制器,是整个SpringMVC的控制中心。用户发出请求,DispatcherServlet接收请求并拦截请求。

2.🔧DispatcherServlet调用HandlerMapping(处理器映射器),HandlerMapping根据请求信息(url)查找handler(根据xml配置以及注解),返回HandlerExecutionChain对象(封装一个Handler对象和多个Handlerinterceptor拦截器)。

3.🔧DispatcherServlet调用HandlerAdapter(处理器适配器)执行对应的Handler(Controller)。

4.🔧Handler(Controller)执行后将ModelAndView返回给HandlerAdapter。

5.🔧HandlerAdapter将ModelAndView传递给DispatcherServlet。

6.🔧DispatcherServlet调用ViewResolver(视图解析器)来解析ModelAndView(根据逻辑视图名modelAndView.setViewName()或者传入Model参数之后return字符串解析成物理视图名)。

7.🔧ViewResolver解析后返回View视图对象给DispatcherServlet。

8.🔧DispatcherServlet根据ViewResolver返回的View视图对象进行视图渲染(模型数据填充到视图中modelAndView.addObject()->${})。

9.🔧将视图(jsp页面)返回给客户端(响应用户)。

1.编写web.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd"
version="5.0">
<!--注册DispatchServlet SpringMVC核心 请求分发器 前端控制器-->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--DispatcherServlet绑定Spring的配置文件:[servletname]-servlet.xml-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc-servlet.xml</param-value>
</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>

2.编写SpringMVC配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<!--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">
<!--编写SpringMVC配置文件-->

<!--添加处理器映射器-->
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
<!--添加处理器适配器-->
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
<!--添加视图解析器
模板引擎 Thymeleaf Freemarker
DispatcherServlet传递的ModelView 将视图解析为Web应用的内部资源,确定来渲染模型的JSP文件的物理位置
-->
<!--页面地址 [视图解析器前缀]+ViewName+[视图解析器后缀]-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver">
<!--前缀-->
<property name="prefix" value="/WEB-INF/jsp/"/>
<!--后缀-->
<property name="suffix" value=".jsp"/>
</bean>
<!--BeanNameUrlHandlerMapping->bean-->
<!--注册HelloController类-->
<!--Handler-->
<bean id="/hello" class="com.ling.controller.HelloController"/>
</beans>

3.编写操作业务Controller

1
2
3
4
5
6
7
8
9
10
11
12
public class HelloController implements Controller {
/*实现Controller接口或使用注解*/
/*需要返回ModelView封装数据和视图*/
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
/*ModelAndView 模型和视图*/
ModelAndView mv = new ModelAndView();
/*封装对象放在ModelAndView*/
mv.addObject("msg","->SpringMVC<-");
mv.setViewName("hello"); /* /WEB-INF/jsp/hello.jsp*/
return mv;
}
}

4.注册该类到Spring容器中

1
<bean id="/hello" class="com.ling.controller.HelloController"/>

5.编写跳转页面,显示ModelandView存放的数据

1
2
3
4
5
6
7
8
9
10
<%-- WEB/WEB-INF/jsp/hello.jsp --%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
${msg}
</body>
</html>

出现404错误,排查jar包是否存在,在IDEA的项目发布中添加lib依赖(Project Structure->Project Settings->Artifacts->对应Spring项目或模块->在WEB-INF下新建lib文件夹->选择该文件夹点击+号->Library Files->Ctrl选择所有添加->重启Tomcat)


注解开发

1.配置web.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd"
version="5.0">
<!--1.注册servlet-->
<servlet>
<servlet-name>SpringMVC</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--通过初始化参数指定SpringMVC配置文件的位置,进行关联-->
<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>
<!--所有请求都会被springmvc拦截 -->
<servlet-mapping>
<servlet-name>SpringMVC</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>

2.编写Spring MVC配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<?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
https://www.springframework.org/schema/mvc/spring-mvc.xsd">

<!-- 自动扫描包让指定包下的注解生效 -->
<context:component-scan base-package="com.ling.controller"/>

<!--
将静态资源的请求转由Web容器处理静态资源的请求,否则Spring MVC会将静态资源的请求当成一个普通请求处理,进而找不到对应处理器出现错误。
对DispatcherServlet传递的URL进行过滤,如果是静态资源的请求,将该请求转由Web应用服务器默认的Servlet处理,从而找到对应的静态资源,如果不是静态资源的请求,由DispatcherServlet继续处理
-->
<mvc:default-servlet-handler />

<!--
支持mvc注解驱动
在spring中一般采用@RequestMapping注解来完成映射关系
使@RequestMapping注解生效,需要在上下文中注册DefaultAnnotationHandlerMapping和AnnotationMethodHandlerAdapter实例
这两个实例分别在类级别和方法级别处理
annotation-driven配置完成上述两个实例的注入
无需配置HandlerMapping和HandlerAdapter(SpringMVC配置三大件 HandlerMapping HandlerAdapter ViewResolver)
-->
<mvc:annotation-driven />

<!-- 手动配置视图解析器 ViewResolver-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
id="internalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
</beans>

3.创建Contrllor类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package com.ling.controller;


import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping("/hello")
public class HelloController {
@RequestMapping("/h1") /* .../hello/h1 */
public String hello(Model model){
/*封装数据*/
model.addAttribute("msg","->Interview h1 Page");
return "hello"; /*视图解析器处理->/WEB-INF/jsp/hello.jsp IDEA可直接点击访问*/
}

@RequestMapping("/h2")
public String h2Method(Model model){
model.addAttribute("msg","->Interview h2 Page");
return "hello";
}
}

4.编写前端View视图页面

1
2
3
4
5
6
7
8
9
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
msg: ${msg}
</body>
</html>

Controller

控制器Controller:

  • 控制器负责提供访问应用程序的行为,通常通过接口定义和注解定义两种方法实现。
  • 控制器负责解析用户的请求并将其转换为一个模型。
  • 在SpringMVC中一个控制器类可以包含多个方法。

1.实现Controller接口(实现该接口的类即为一个控制器)

1
2
3
4
5
6
@FunctionalInterface 
public interface Controller {
@Nullable
/*处理请求并返回ModelAndView对象*/
ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception;
}
1
2
3
4
5
6
7
8
9
10
public class ControllerDemo implements Controller {

@Override
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
ModelAndView mv = new ModelAndView();
mv.addObject("msg","Controller1");
mv.setViewName("test");
return mv;
}
}

2.使用注解@Controller

1.@Controller注解用于声明Spring类的实例是一个控制器。

2.Spring使用扫描机制来找到应用程序中所有基于注解的控制器类,需要在配置文件中声明组件扫描。

1
2
3
4
5
6
7
8
@Controller
public class ControllerDemo2 {
@RequestMapping("/demo2")
public String test(Model model){
model.addAttribute("msg","Controller2");
return "test";
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<!--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"
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">
<context:component-scan base-package="com.ling.controller"/>
<!--从 Spring 4.0 开始,如果不配置处理器映射器、处理器适配器和视图解析器,Spring 会使用默认配置来完成相应工作。-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
id="internalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
<bean name="/demo" class="com.ling.controller.ControllerDemo"/>
</beans>

<!--web.xml-->
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd"
version="5.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>

RequestMapping

@RequestMapping注解用于映射url到Controller类或Controller类中特定方法,可用于类或方法上。用于类上可表示类中的所有响应请求的方法都是以该地址作为父地址。

1.注解在方法上

1
2
3
4
5
6
7
8
9
@Controller
public class ControllerDemo2 {
/*访问路径 http://localhost:8080/项目名(在Tomcat->Deployment->Application context配置)/d2*/
@RequestMapping("/d2")
public String test(Model model){
model.addAttribute("msg","->Demo2");
return "test";
}
}

2.注解类和方法

1
2
3
4
5
6
7
8
9
10
@Controller
@RequestMapping("/Demo")
public class ControllerDemo2 {
/*访问路径 http://localhost:8080/项目名(在Tomcat->Deployment->Application context配置)/Demo/d2*/
@RequestMapping("/d2")
public String test(Model model){
model.addAttribute("msg","Demo->Demo2");
return "test";
}
}

RestFUL风格

1.表现层状态转换(Representational State Transfer,REST)是Roy Thomas Fielding博士于2000年在他的博士论文中提出来的一种万维网软件架构风格,目的是便于不同软件/程序在网络(例如互联网)中互相传递信息。表现层状态转换是基于超文本传输协议(HTTP)之上而确定的一组约束和属性,是一种设计提供万维网络服务的软件构建风格。符合或兼容于这种架构风格(简称为 REST 或 RESTful)的网络服务,允许客户端发出以统一资源标识符访问和操作网络资源的请求,而与预先定义好的无状态操作集一致化。因此表现层状态转换提供了在互联网络的计算系统之间,彼此资源可交互使用的协作性质(interoperability)。相对于其它种类的网络服务,例如SOAP服务,则是以本身所定义的操作集,来访问网络上的资源。

2.REST是设计风格而不是标准。REST通常基于HTTP、URI、XML以及HTML这些现有的广泛流行的协议和标准。

  • 资源是由URI来指定。

  • 对资源的操作包括获取、创建、修改和删除,这些操作正好对应HTTP协议提供的GET、POST、PUT和DELETE方法。(可以通过不同的请求方式来实现不同的效果)

  • 通过操作资源的表现形式来操作资源。

  • 资源的表现形式则是XML或者HTML,取决于读者是机器还是人、是消费Web服务的客户软件还是Web浏览器。当然也可以是任何其他的格式,例如JSON。

3.可重新表达的状态迁移的特征

  • Uniform Interface:统一接口。
    1. 以资源为基础
    2. 通过重表达的客户端可以管理原资源
    3. 返回信息足够描述自己
    4. 超媒体是应用状态的引擎
  • Stateless:无状态。
  • Cacheable:可缓存。
  • Client-Server:客户服务器分离模式,任何一个客户端与服务器都是可替换的。
  • Layered System:分层的系统,客户端不知道他联系的是不是最终服务器。
  • Code on Demand(可选):服务器可以将能力扩展到客户端,如果客户端可以执行的话。这个功能是可选择的

4.REST优点

  • 可更高效利用缓存来提高响应速度
  • 通讯本身的无状态性可以让不同的服务器的处理一系列请求中的不同请求,提高服务器的扩展性
  • 浏览器即可作为客户端,简化软件需求
  • 相对于其他叠加在HTTP协议之上的机制,REST的软件依赖性更小
  • 不需要额外的资源发现机制
  • 在软件技术演进中的长期的兼容性更好

5.Example

  • 列举所有商品:
1
GET http://www.store.com/products
  • 呈现某一件商品:
1
2
GET http://www.store.com/products/12345
#传统 http://www.store.com/products?id=12345
  • 下单购买:
1
2
3
4
POST http://www.store.com/orders
<purchase-order>
<item> ... </item>
</purchase-order>

在SpringMVC中可以使用@PathVariable注解,让方法参数的值绑定到对应的URI模板变量上。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
@Controller
public class RestFulController {
/*传统 http://localhost:8080/add?a=1&b=5 */
/*RestFul http://localhost:8080/add/a/b */
/*对与可填可不填的参数,使用@PathVariable(required = false)*/
@RequestMapping("/add/{a}/{b}")
public String test1(@PathVariable int a,@PathVariable int b, Model model){
model.addAttribute("msg","Result: "+(a+b));
return "test";
}

/*
组合注解:
GetMapping
PostMapping
PutMapping
DeleteMapping
PatchMapping
*/
@RequestMapping(value = "/mul/{a}/{b}",method = RequestMethod.GET)
public String test2(@PathVariable int a,@PathVariable int b, Model model){
model.addAttribute("msg","Get Result: "+(a*b));
return "test";
}
@GetMapping(value = "/division/{a}/{b}")
public String test3(@PathVariable int a,@PathVariable int b, Model model){
model.addAttribute("msg","Get Result: "+(a/b));
return "test";
}
/*
1.postman
2.jsp
<form action="/division/4/2" method="post">
<input type="submit">
</form>
*/
@PostMapping(value = "/division/{a}/{b}")
public String test4(@PathVariable int a,@PathVariable int b, Model model){
model.addAttribute("msg","Post Result: "+(a/b));
return "test";
}
}

重定向和转发

1.ModelAndView:设置ModelAndView,视图解析器根据View名称返回真正的视图对象。

1
2
3
4
5
6
7
8
9
public class ControllerDemo implements Controller {
@Override
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
ModelAndView mv = new ModelAndView();
mv.addObject("msg","Controller1");
mv.setViewName("test");
return mv;
}
}
1
2
3
4
5
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
id="internalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>

2.Servlet API

通过设置ServletAPI,不需要视图解析器

  • 通过HttpServletResponse进行输出或者重定向
  • 通过HttpServletRequest实现转发
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Controller
public class ServletController {
@RequestMapping("/rw")
public void test1(HttpServletRequest req, HttpServletResponse resp) throws IOException {
HttpSession session = req.getSession();

resp.getWriter().print("<h1>Method test1</h1>");
resp.getWriter().print("<p>"+session.getId()+"</p>");
}
@RequestMapping("/rr")
public void test2(HttpServletRequest req, HttpServletResponse resp) throws IOException {
resp.sendRedirect("/index.jsp");
}
@RequestMapping("/rd")
public void test3(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {
req.setAttribute("msg","Method test3");
req.getRequestDispatcher("/WEB-INF/jsp/test.jsp").forward(req,resp);
}
}

3.SpringMVC

  • 无视图解析器(ViewResolver)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package com.ling.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class NotViewReController {
/*转发*/
@RequestMapping("/rsp/m1")
public String test1(){
return "/index.jsp";
}
/*转发*/
@RequestMapping("/rsp/m2")
public String test2(){
return "forward:/index.jsp";
}
/*重定向*/
@RequestMapping("/rsp/m3")
public String test3(){
return "redirect:/index.jsp";
}
@RequestMapping("/rsp/m4")
public String test4(Model model){
model.addAttribute("msg","-Method test4-");
return "forward:/WEB-INF/jsp/test.jsp";
}
}
  • 有视图解析器(ViewResolver)
1
2
3
4
5
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
id="internalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
1
2
3
4
5
6
7
8
9
10
11
12
13
@Controller
public class ViewReController {
/*转发*/
@RequestMapping("/test")
public String test1(){
return "test";
}
/*重定向*/
@RequestMapping("/test2")
public String test2(){
return "redirect:/index.jsp";
}
}

数据处理

  • 处理提交数据

1.提交的域名称和处理方法的参数名一致

1
2
3
4
5
6
7
/*http://localhost:8080/hello?name=SpringMVC*/
@RequestMapping("/hello")
public String test1(String name, Model model){
model.addAttribute("msg","Hello "+name);
System.out.println("Name:"+name);
return "test";
}

2.提交的域名称和处理方法的参数名不一致

1
2
3
4
5
6
7
/*http://localhost:8080/helloUser?username=world*/
@RequestMapping("/helloUser")
public String test2(@RequestParam("username") String name, Model model){
model.addAttribute("msg","Hello "+name);
System.out.println("Name:"+name);
return "test";
}

3.提交的对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
public class User {
private String name;
private int id;
private int age;
/*
值为null或初始值

1.没有对应的构造函数或者setter方法
2.前端传递的参数名和对象名不一致
*/
public User(String name, int id, int age) {
this.name = name;
this.id = id;
this.age = age;
}

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

public void setId(int id) {
this.id = id;
}

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

@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", id=" + id +
", age=" + age +
'}';
}
}
1
2
3
4
5
6
7
/*http://localhost:8080/userhello?name=Ming&id=6&age=14*/
@RequestMapping("/userhello")
public String test3(User user,Model model){
model.addAttribute("msg","Hello "+ user);
System.out.println(user.toString());
return "test";
}

  • 数据显示到前端

1.ModelAndView

1
2
3
4
5
6
7
8
9
public class ControllerDemo3 implements Controller {
@Override
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
ModelAndView mv = new ModelAndView();
mv.addObject("msg","Method with ModelAndView");
mv.setViewName("test");
return mv;
}
}

2.ModelMap

1
2
3
4
5
@RequestMapping("/test")
public String hello1(String name, ModelMap modelMap){
modelMap.addAttribute("msg","method with ModelMap"+" and name: "+name);
return "test";
}

3.Model

1
2
3
4
5
@RequestMapping("/test2")
public String hello2(String name, Model model){
model.addAttribute("msg","method with Model"+" and name: "+name);
return "test";
}

ModelMap 继承了 LinkedMap ,除了实现了自身的方法,同样的继承 LinkedMap 的方法和特性。

ModelAndView 可以在储存数据的同时,可以进行设置返回的逻辑视图,进行控制展示层的跳转。


中文乱码

1
2
3
4
5
6
7
8
9
@Controller
public class EncodingController {
@PostMapping("/e/t1")
public String test1(String name, Model model){
System.out.println(name);
model.addAttribute("msg",name);
return "test";
}
}
1
2
3
4
5
6
7
8
9
10
11
12
<%@ 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>

1.自定义Fileter

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class EncodingFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {

}
@Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain filterChain) throws IOException, ServletException {
req.setCharacterEncoding("utf-8");
resp.setCharacterEncoding("utf-8");
filterChain.doFilter(req,resp);
}

@Override
public void destroy() {

}
}

web.xml中注册

1
2
3
4
5
6
7
8
9
10
<!--/ 无法对jsp文件进行过滤-->
<filter>
<filter-name>encoding</filter-name>
<filter-class>com.ling.filter.EncodingFilter</filter-class>
</filter>

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

2.使用Spring框架的过滤器

1
2
3
4
5
6
7
8
9
10
11
12
<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>

乱码问题仍然无法解决

1.修改tomcat配置文件:

1
2
3
<Connector URIEncoding="utf-8" port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />

2.自定义过滤器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
/*
解决get和post请求 全部乱码的过滤器
*/
public class GenericEncodingFilter implements Filter {

@Override
public void destroy() {
}

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
//处理response的字符编码
HttpServletResponse myResponse=(HttpServletResponse) response;
myResponse.setContentType("text/html;charset=UTF-8");
// 转型为与协议相关对象
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
// 对request包装增强
HttpServletRequest myrequest = new MyRequest(httpServletRequest);
chain.doFilter(myrequest, response);
}

@Override
public void init(FilterConfig filterConfig) throws ServletException {
}

}

//自定义request对象,HttpServletRequest的包装类
class MyRequest extends HttpServletRequestWrapper {

private HttpServletRequest request;
//是否编码的标记
private boolean hasEncode;
//定义一个可以传入HttpServletRequest对象的构造函数,以便对其进行装饰
public MyRequest(HttpServletRequest request) {
super(request);// super必须写
this.request = request;
}

// 对需要增强方法 进行覆盖
@Override
public Map getParameterMap() {
// 先获得请求方式
String method = request.getMethod();
if (method.equalsIgnoreCase("post")) {
// post请求
try {
// 处理post乱码
request.setCharacterEncoding("utf-8");
return request.getParameterMap();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
} else if (method.equalsIgnoreCase("get")) {
// get请求
Map<String, String[]> parameterMap = request.getParameterMap();
if (!hasEncode) { // 确保get手动编码逻辑只运行一次
for (String parameterName : parameterMap.keySet()) {
String[] values = parameterMap.get(parameterName);
if (values != null) {
for (int i = 0; i < values.length; i++) {
try {
// 处理get乱码
values[i] = new String(values[i]
.getBytes("ISO-8859-1"), "utf-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
}
}
hasEncode = true;
}
return parameterMap;
}
return super.getParameterMap();
}

//取一个值
@Override
public String getParameter(String name) {
Map<String, String[]> parameterMap = getParameterMap();
String[] values = parameterMap.get(name);
if (values == null) {
return null;
}
return values[0]; // 取回参数的第一个值
}

//取所有值
@Override
public String[] getParameterValues(String name) {
Map<String, String[]> parameterMap = getParameterMap();
String[] values = parameterMap.get(name);
return values;
}
}

JSON

1.JSON(JavaScript Object Notation)是由Douglas Crockford构想和设计的一种轻量级资料交换格式。其内容由属性和值所组成,因此也有易于阅读和处理的优势。JSON是独立于编程语言的资料(文本)格式,其不仅是JavaScript的子集,也采用了C语言家族的习惯用法,目前也有许多编程语言都能够将其解析和字符串化,其广泛使用的程度也使其成为通用的资料格式。JSON格式是1999年《JavaScript Programming Language, Standard ECMA-262 3rd Edition》的子集合,所以可以在JavaScript以eval()函数(javascript通过eval()调用解析器)读入。不过这并不代表JSON无法使用于其他语言,事实上几乎所有与网络开发相关的语言都有JSON函数库。

2.JSON的基本数据类型:

  • 数值:十进制数,不能有前导0,可以为负数,可以有小数部分。还可以用e或者E表示指数部分。不能包含非数,如NaN。不区分整数与浮点数。JavaScript用双精度浮点数表示所有数值。

  • 字符串:以双引号""括起来的零个或多个Unicode码位。支持反斜杠开始的转义字符序列。

  • 布尔值:表示为true或者false

  • 数组:有序的零个或者多个值。每个值可以为任意类型。序列表使用方括号[]括起来。元素之间用逗号,分割。形如:[value, value]

  • 对象:若干无序的"键-值对"(key-value pairs),其中键只能是字符串。建议但不强制要求对象中的键是独一无二的。对象以花括号{开始,并以}结束。键-值对之间使用逗号分隔键与值之间用冒号:分割

  • 空值:值写为null

3.token(6种标点符号、字符串、数值、3种字面量)之间可以存在有限的空白符并被忽略。四个特定字符被认为是空白符:空格符、水平制表符、回车符、换行符。空白符不能出现在token内部(但空格符可以出现在字符串内部)。

4.JSON标准不允许有字节序掩码,不提供注释的句法。

5.一个有效的JSON文档的根节点必须是一个对象或一个数组。

6.JSON交换时必须编码为UTF-8。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
{
"firstName": "John",
"lastName": "Smith",
"sex": "male",
"age": 25,
"address":
{
"streetAddress": "21 2nd Street",
"city": "New York",
"state": "NY",
"postalCode": "10021"
},
"phoneNumber":
[
{
"type": "home",
"number": "212 555-1234"
},
{
"type": "fax",
"number": "646 555-4567"
}
]
}

  • 从 JSON 字符串转换为 JavaScript 对象,使用 JSON.parse() 方法:
1
var obj = JSON.parse('{"a": "Hello", "b": "World"}');
  • 从 JavaScript 对象转换为 JSON 字符串,使用 JSON.stringify() 方法:
1
var json = JSON.stringify({a: 'Hello', b: 'World'});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script type="text/javascript">
var user={
name:"JavaScript",
age:3,
sex:"male"
}
var json = JSON.stringify(user)
var obj = JSON.parse(json)
console.log(json)
console.log(obj)
</script>
</head>
<body>
</body>
</html>

Java JSON

1.导入依赖,配置web.xml pom.xml springmvc-servlet.xml

1
2
3
4
5
6
7
<!--500错误在lib下导入Jackson对应库文件-->
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.13.0</version>
</dependency>

2.编写对应实体类

1
2
3
4
5
6
7
8
9
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private String name;
private int id;
private String sex;

}

3.编写对应Controller类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Controller
/*@RestController可代替@Controller和@ResponseBody*/
public class UserController {
/*解决中文乱码*/
@RequestMapping("/j1")
@ResponseBody /*不会走视图解析器,会直接返回一个字符串*/
public String jsonDemo() throws JsonProcessingException {
/*Jackson ObjectMapper*/
ObjectMapper mapper = new ObjectMapper();
User user = new User("伍六",12,"male");
String str = mapper.writeValueAsString(user);
/*字符串直接显示在页面*/
return str;
}
}

乱码问题还可以在springmvc的配置文件中加入消息StringHttpMessageConverter转换配置。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<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>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
@RestController
/*相当于@Controller+@ResponseBody两个注解的结合,返回json数据不需要在方法前面加@ResponseBody注解*/
public class UserController {
@RequestMapping("/j2")
public String jsonDemo() throws JsonProcessingException {

ObjectMapper mapper = new ObjectMapper();
List<User> userList = new ArrayList<User>();
User user = new User("伍六",12,"male");
User user1 = new User("七八",12,"male");
User user2 = new User("九十",12,"female");
userList.add(user);
userList.add(user1);
userList.add(user2);
String str = mapper.writeValueAsString(userList);
return str;
}
@RequestMapping("/j3")
public String jsonDemo2() throws JsonProcessingException {

ObjectMapper mapper = new ObjectMapper();
/*不使用时间戳*/
mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
Date date = new Date();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
/*ObjectMapper 时间解析后的默认格式为 Timestamp 时间戳*/
/*1.String str = mapper.writeValueAsString(simpleDateFormat.format(date));*/
mapper.setDateFormat(simpleDateFormat);
return mapper.writeValueAsString(date);
/*1.return str;*/
}
}

4.提取出JSON工具类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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 mapper = new ObjectMapper();
mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
SimpleDateFormat sdf = new SimpleDateFormat(dateFormat);
mapper.setDateFormat(sdf);
try {
return mapper.writeValueAsString(object);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return null;
}
}
1
2
3
4
5
6
@RequestMapping("/j2")
public String jsonDemo() throws JsonProcessingException {
Date date = new Date();
String json = JsonUtils.getJson(date);
return json;
}

FastJSON

1.fastjson.jar是阿里开发的一款用于Java开发的包,可以方便的实现json对象与JavaBean对象的转换,实现JavaBean对象与json字符串的转换,实现json对象与json字符串的转换。

2.fastjson三个主要类:

  • JSONObject:json对象

    • JSONObject实现了Map接口
    • JSONObject对应json对象,通过各种形式的get()方法可以获取json对象中的数据,也可用如size(),isEmpty()等方法获取"键:值"对的个数和判断是否为空
  • JSONArray:json对象数组

    • 内部由List接口中的方法完成操作
1
2
3
4
5
6
<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.78</version>
</dependency>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class FastJsonDemo {
public static void main(String[] args) {
//创建一个对象
User user1 = new User("Model1", 1, "male");
User user2 = new User("Model2", 2, "male");
User user3 = new User("Model3", 3, "female");
User user4 = new User("Model4", 4, "female");
List<User> list = new ArrayList<User>();
list.add(user1);
list.add(user2);
list.add(user3);
list.add(user4);
/*Java对象 转 JSON字符串*/
String str1 = JSON.toJSONString(list);
System.out.println("JSON.toJSONString(list)==>"+str1);
String str2 = JSON.toJSONString(user1);
System.out.println("JSON.toJSONString(user1)==>"+str2);
/*JSON字符串转Java对象*/
User jp_user1=JSON.parseObject(str2,User.class);
System.out.println("JSON.parseObject(str2,User.class)==>"+jp_user1);
/*Java对象转JSON对象*/
JSONObject jsonObject1 = (JSONObject) JSON.toJSON(user2);
System.out.println("(JSONObject) JSON.toJSON(user2)==>"+jsonObject1.getString("name"));
/*JSON对象转Java对象*/
User to_java_user = JSON.toJavaObject(jsonObject1, User.class);
System.out.println("JSON.toJavaObject(jsonObject1, User.class)==>"+to_java_user);
}
}

SSM整合

1.搭建数据库

1
2
3
4
5
6
7
8
9
10
11
12
13
14
CREATE DATABASE ssmbuild;
USE ssmbuild;
CREATE TABLE `books`(
`bookID` INT NOT NULL AUTO_INCREMENT COMMENT '书id',
`bookName` VARCHAR(100) NOT NULL COMMENT '书名',
`bookCounts` INT NOT NULL COMMENT '数量',
`detail` VARCHAR(200) NOT NULL COMMENT '描述',
KEY `bookID`(`bookID`)
)ENGINE=INNODB DEFAULT CHARSET=utf8;

INSERT INTO `books`(`bookID`,`bookName`,`bookCounts`,`detail`)VALUES
(1,'Java',1,'Java核心技术'),
(2,'MySQL',10,'MySQL必知必会'),
(3,'Linux',5,'鸟哥的Linux私房菜')

2.新建Maven项目,添加Web支持

  • pom.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
<?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>org.noob</groupId>
<artifactId>SSM</artifactId>
<version>1.0-SNAPSHOT</version>

<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>

<!--依赖-->
<dependencies>

<!--Junit-->
<!-- https://mvnrepository.com/artifact/junit/junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>

<!--数据库驱动-->
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.27</version>
</dependency>

<!--数据库连接池 c3p0:dbcp-->
<!-- https://mvnrepository.com/artifact/com.mchange/c3p0 -->
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.5</version>
</dependency>

<!--servlet-->
<!-- 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>

<!--jsp-->
<!-- 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>

<!--jstl-->
<!-- https://mvnrepository.com/artifact/javax.servlet/jstl -->
<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.7</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.6</version>
</dependency>

<!--Spring-->
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.13</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.13</version>
</dependency>

<!--lombok-->
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.20</version>
<scope>provided</scope>
</dependency>
</dependencies>

<!--静态资源导出-->
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</build>
</project>

3.编写数据库对应实体类

1
2
3
4
5
6
7
8
9
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Books {
private int bookID;
private String bookName;
private int bookCounts;
private String detail;
}

4.配置Mybatis核心文件以及配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--由Spring配置数据源-->

<!--设置别名-->
<typeAliases>
<package name="com.ling.pojo"/>
</typeAliases>

<mappers>
<mapper class="com.ling.dao.BookMapper"/>
</mappers>
</configuration>
1
2
3
4
5
jdbc.driver=com.mysql.cj.jdbc.Driver
# MySQL8.0+需要增加时区配置
jdbc.url=jdbc:mysql://localhost:3306/ssmbuild?useSSL=true&useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
jdbc.username=root
jdbc.password=0513

5.编写数据库CRUD接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package com.ling.dao;

import com.ling.pojo.Books;

import java.util.List;

public interface BookMapper {
int addBook(Books books);
int deleteBook(int id);
int updateBook(Books books);
Books queryBookByID(int id);
List<Books> queryAllBook();
/*模糊查询*/
List<Books> queryBookByName(String bookName);
}

6.编写接口对应mapper

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ling.dao.BookMapper">

<insert id="addBook" parameterType="Books">
insert into ssmbuild.books(bookName, bookCounts, detail)
values (#{bookName}, #{bookCounts}, #{detail})
</insert>

<delete id="deleteBook" parameterType="int">
delete from ssmbuild.books where bookID = #{bookID};
</delete>

<update id="updateBook" parameterType="Books">
update ssmbuild.books set bookName=#{bookName}, bookCounts=#{bookCounts}, detail=#{detail}
where bookID=#{bookID};
</update>

<select id="queryBookByID" resultType="Books">
select * from ssmbuild.books
where bookID=#{bookID}
</select>

<select id="queryAllBook" resultType="Books">
select * from ssmbuild.books
</select>


<select id="queryBookByName" resultType="Books">
select * from ssmbuild.books
where bookName like concat('%',#{bookName},'%');
</select>
</mapper>

提示信息:

  • 在settings–>Languages&Frameworks–>SQL Dialects中配置数据库类型,将项目添加进去
  • 在IDEA中连接Mysql数据库对应库的database

7.编写Service层接口

1
2
3
4
5
6
7
8
public interface BookService {
int addBook(Books books);
int deleteBook(int id);
int updateBook(Books books);
Books queryBookByID(int id);
List<Books> queryAllBook();
List<Books> queryBookByName(String bookName);
}

8.编写Service层接口实现类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public class BookServiceImpl implements BookService{
/*service调用dao层*/
private BookMapper bookMapper;
public void setBookMapper(BookMapper bookMapper){
this.bookMapper=bookMapper;
}
public int addBook(Books books) {
return bookMapper.addBook(books);
}

@Override
public int deleteBook(int id) {
return bookMapper.deleteBook(id);
}

@Override
public int updateBook(Books books) {
return bookMapper.updateBook(books);
}

@Override
public Books queryBookByID(int id) {
return bookMapper.queryBookByID(id);
}

@Override
public List<Books> queryAllBook() {
return bookMapper.queryAllBook();
}

@Override
public List<Books> queryBookByName(String bookName) {
return bookMapper.queryBookByName(bookName);
}
}

9.编写Spring配置文件

  • spring-dao.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<?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"
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">
<!--关联数据库配置文件-->
<context:property-placeholder location="classpath:database.properties"/>
<!--连接池 dbcp c3p0 druid hikari-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driver}"/>
<property name="jdbcUrl" value="${jdbc.url}"/>
<property name="user" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>

<!-- c3p0连接池的私有属性 -->
<property name="maxPoolSize" value="30"/>
<property name="minPoolSize" value="10"/>
<!-- 关闭连接后不自动commit -->
<property name="autoCommitOnClose" value="false"/>
<!-- 获取连接超时时间 -->
<property name="checkoutTimeout" value="10000"/>
<!-- 获取连接失败重试次数 -->
<property name="acquireRetryAttempts" value="2"/>
</bean>
<!--sqlSessionFactory-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<!--绑定Mybatis配置文件-->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
</bean>
<!--配置dao接口扫描包,动态实现dao接口注入Spring容器中-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!--注入sqlSessionFactory-->
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
<!--扫描dao包-->
<property name="basePackage" value="com.ling.dao"/>
</bean>
</beans>
  • spring-service.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?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"
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">
<!--扫描service下包-->
<context:component-scan base-package="com.ling.service"/>
<!--BookServiceImpl注入到Spring-->
<bean id="BookServiceImpl" class="com.ling.service.BookServiceImpl">
<!--自动装配BookMapper属性-->
<property name="bookMapper" ref="bookMapper"/>
</bean>
<!--声明式事务管理-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--注入数据源-->
<property name="dataSource" ref="dataSource"/>
</bean>
</beans>
  • applicationcontext.xml
1
2
3
4
5
6
7
8
<?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">
<import resource="classpath:spring-dao.xml"/>
<import resource="classpath:spring-service.xml"/>
<import resource="classpath:spring-mvc.xml"/>
</beans>
  • spring-mvc.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<?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:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">

<!--注解驱动-->
<mvc:annotation-driven/>
<!--静态资源过滤-->
<mvc:default-servlet-handler/>
<!--扫描包 controller-->
<context:component-scan base-package="com.ling.controller"/>

<!--视图解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>

<!-- 扫描web相关的bean -->
<context:component-scan base-package="com.ling.controller" />
</beans>

10.编写web.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<?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">

<!--DispatchServlet-->
<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>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>

<!--乱码过滤-->
<filter>
<filter-name>encodingFilter</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>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

<!--Session-->
<session-config>
<session-timeout>15</session-timeout>
</session-config>
</web-app>

11.编写Controller类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
@Controller
@RequestMapping("/book")
public class BookController {
/*controller调用service层*/
@Autowired
@Qualifier("BookServiceImpl")
private BookService bookService;

@RequestMapping("/allBook")
public String list(Model model){
List<Books>list = bookService.queryAllBook();
model.addAttribute("list",list);
return "allBook";
}

@RequestMapping("/toAddBook")
public String toAddPaper() {
return "addBook";
}
@RequestMapping("/addBook")
public String addPaper(Books books) {
System.out.println(books);
bookService.addBook(books);
return "redirect:/book/allBook";
}
/*跳转到修改页面*/
@RequestMapping("/toUpdateBook")
public String toUpdateBook(Model model, int id) {
Books books = bookService.queryBookByID(id);
System.out.println(books);
model.addAttribute("book",books );
return "updateBook";
}

@RequestMapping("/updateBook")
public String updateBook(Model model, Books book) {
System.out.println(book);
bookService.updateBook(book);
return "redirect:/book/allBook";
}

@RequestMapping("/del/{bookId}")
public String deleteBook(@PathVariable("bookId") int id) {
bookService.deleteBook(id);
return "redirect:/book/allBook";
}
@RequestMapping("/queryBook")
public String queryBook(String queryBookName,Model model){
List<Books> list = bookService.queryBookByName(queryBookName);
if(list.isEmpty()){
model.addAttribute("error","不存在该书籍");
}
model.addAttribute("list",list);

return "allBook";
}
}

12.编写前端JSP页面

  • index.jsp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>书籍展示页面</title>
<style>
a{
text-decoration: none;
color: black;
font-size: 18px;
}
h3{
width:180px;
height: 38px;
margin: 100px auto;
text-align: center;
line-height: 38px;
background: deepskyblue;
border-radius: 5px;
}

</style>
</head>
<body>
<h3>
<a href="${pageContext.request.contextPath}/book/allBook">进入书籍首页</a>
</h3>
</body>
</html>
  • WEB-INF/jsp/addBook.jsp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>

<html>
<head>
<title>新增书籍</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- 引入 Bootstrap -->
<link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="container">

<div class="row clearfix">
<div class="col-md-12 column">
<div class="page-header">
<h1>
<small>新增书籍</small>
</h1>
</div>
</div>
</div>
<form action="${pageContext.request.contextPath}/book/addBook" method="post">
书籍名称:<input type="text" name="bookName"><br><br><br>
书籍数量:<input type="text" name="bookCounts"><br><br><br>
书籍详情:<input type="text" name="detail"><br><br><br>
<input type="submit" value="添加">
</form>
</div>
  • WEB-INF/jsp/allBook.jsp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>书籍列表</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- 引入 Bootstrap -->
<link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>

<div class="container">

<div class="row clearfix">
<div class="col-md-12 column">
<div class="page-header">
<h1>
<small>书籍列表 —— 显示所有书籍</small>
</h1>
</div>
</div>
</div>

<div class="row">
<div class="col-md-4 column">
<a class="btn btn-primary" href="${pageContext.request.contextPath}/book/toAddBook">新增</a>
</div>
<div class="form-inline">
<%-- 查询书籍--%>
<form action="${pageContext.request.contextPath}/book/queryBook" method="post" style="float: right">
<span style="color: red;font-weight: bold">${error}</span>
<input type="text" name="queryBookName" class="form-control" placeholder="输入需要查询的书籍">
<input type="submit" value="查询" class="btn btn-primary">
</form>
</div>
</div>

<div class="row clearfix">
<div class="col-md-12 column">
<table class="table table-hover table-striped">
<thead>
<tr>
<th>书籍编号</th>
<th>书籍名字</th>
<th>书籍数量</th>
<th>书籍详情</th>
<th>操作</th>
</tr>
</thead>

<tbody>
<c:forEach var="book" items="${requestScope.get('list')}">
<tr>
<td>${book.getBookID()}</td>
<td>${book.getBookName()}</td>
<td>${book.getBookCounts()}</td>
<td>${book.getDetail()}</td>
<td>
<!--从原有查询页面获得ID传给toUpdateBook对应方法-->
<a href="${pageContext.request.contextPath}/book/toUpdateBook?id=${book.getBookID()}">更改</a> |
<a href="${pageContext.request.contextPath}/book/del/${book.getBookID()}">删除</a>
</td>
</tr>
</c:forEach>
</tbody>
</table>
</div>
</div>
</div>
  • WEB-INF/jsp/updateBook.jsp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>修改信息</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- 引入 Bootstrap -->
<link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="container">

<div class="row clearfix">
<div class="col-md-12 column">
<div class="page-header">
<h1>
<small>修改信息</small>
</h1>
</div>
</div>
</div>

<!--通过toUpdateBook获取原来数据,同时上传更新数据给updateBook-->
<form action="${pageContext.request.contextPath}/book/updateBook" method="post">
<!--前端传递隐藏域-->
<input type="hidden" name="bookID" value="${book.getBookID()}"/>
书籍名称:<input type="text" name="bookName" value="${book.getBookName()}"/>
书籍数量:<input type="text" name="bookCounts" value="${book.getBookCounts()}"/>
书籍详情:<input type="text" name="detail" value="${book.getDetail() }"/>
<input type="submit" value="提交"/>
</form>

</div>

Ajax

1.AJAX(Asynchronous JavaScript and XML,异步的JavaScript与XML技术),指的是一套综合了多项技术的浏览器端网页开发技术。Ajax的概念由Jesse James Garrett所提出。

2.传统的Web应用允许用户端填写表单(form),当提交表单时就向网页服务器发送一个请求。服务器接收并处理传来的表单,然后送回一个新的网页,但这个做法浪费了许多带宽,因为在前后两个页面中的大部分HTML码往往是相同的。由于每次应用的沟通都需要向服务器发送请求,应用的回应时间依赖于服务器的回应时间。这导致了用户界面的回应比本机应用慢得多。

与此不同,AJAX应用可以仅向服务器发送并取回必须的数据,并在客户端采用JavaScript处理来自服务器的回应(更新部分网页)。因为在服务器和浏览器之间交换的数据大量减少,服务器回应更快了。同时,很多的处理工作可以在发出请求的客户端机器上完成,因此Web服务器的负荷也减少了(Google Suggest应用搜索单词)。

3.类似于DHTML或LAMP,AJAX不是指一种单一的技术,而是有机地利用了一系列相关的技术。虽然其名称包含XML,但实际上数据格式可以由JSON代替以进一步减少数据量。而客户端与服务器也并不需要异步。一些基于AJAX的"派生/合成"式(derivative/composite)的技术也正在出现,如AFLAX。


1.使用jQuery(JavaScript库)中提供的AJAX方法,本质就是对JS原生XMLHttpRequest(XHR)进行封装,通过这些方法能够使用 HTTP Get 和 HTTP Post 从远程服务器上请求文本、HTML、XML 或 JSON - 同时能够把这些外部数据直接载入网页的被选元素中。

jQuery库拥有完整的 Ajax 兼容套件。其中的函数和方法允许我们在不刷新浏览器的情况下从服务器加载数据。

函数 描述
jQuery.ajax() 执行异步 HTTP (Ajax) 请求。
jQuery.ajaxSetup() 设置将来的 Ajax 请求的默认值。
jQuery.get() 使用 HTTP GET 请求从服务器加载数据。
jQuery.post() 使用 HTTP POST 请求从服务器加载数据。
jQuery.getScript() 使用 HTTP GET 请求从服务器加载 JavaScript 文件,然后执行该文件。
jQuery.param() 创建数组或对象的序列化表示,适合在 URL 查询字符串或 Ajax 请求中使用。

jQuery ajax - ajax()方法

1
jQuery.ajax([settings])
参数 描述
settings 可选。用于配置 Ajax 请求的键值对集合。可以通过 $.ajaxSetup() 设置任何选项的默认值。
  • options

    类型:Object可选。AJAX 请求设置。所有选项都是可选的。

  • async

    类型:Boolean默认值: true。默认设置下,所有请求均为异步请求。如果需要发送同步请求,请将此选项设置为 false。注意,同步请求将锁住浏览器,用户其它操作必须等待请求完成才可以执行。

  • beforeSend(XHR)

    类型:Function 发送请求前可修改 XMLHttpRequest 对象的函数,如添加自定义 HTTP 头。

  • cache

    类型:Boolean 默认值: true,dataType 为 script 和 jsonp 时默认为 false。设置为 false 将不缓存此页面。jQuery 1.2 新功能。

  • complete(XHR, TS)

    类型:Function 请求完成后回调函数 (请求成功或失败之后均调用)。参数: XMLHttpRequest 对象和一个描述请求类型的字符串。这是一个 Ajax 事件。

  • contentType

    类型:String 默认值: “application/x-www-form-urlencoded”。

  • context

    类型:Object 这个对象用于设置 Ajax 相关回调函数的上下文。

  • data

    类型:String 发送到服务器的数据。将自动转换为请求字符串格式。

  • dataFilter

    类型:Function 给 Ajax 返回的原始数据的进行预处理的函数。提供 data 和 type 两个参数:data 是 Ajax 返回的原始数据,type 是调用 jQuery.ajax 时提供的 dataType 参数。函数返回的值将由 jQuery 进一步处理。

  • dataType

    类型:String 预期服务器返回的数据类型。如果不指定,jQuery 将自动根据 HTTP 包 MIME 信息来智能判断,比如 XML MIME 类型就被识别为 XML。在 1.4 中,JSON 就会生成一个 JavaScript 对象,而 script 则会执行这个脚本。随后服务器端返回的数据会根据这个值解析后,传递给回调函数。

    可用值:

    • “xml”: 返回 XML 文档,可用 jQuery 处理。
    • “html”: 返回纯文本 HTML 信息;包含的 script 标签会在插入 dom 时执行。
    • “script”: 返回纯文本 JavaScript 代码。
    • “json”: 返回 JSON 数据。
    • “jsonp”: JSONP 格式。
    • “text”: 返回纯文本字符串。
  • error

    类型:Function 默认值: 自动判断 (xml 或 html)。

  • global

    类型:Boolean 是否触发全局 AJAX 事件。默认值: true。设置为 false 将不会触发全局 AJAX 事件,如 ajaxStart 或 ajaxStop 可用于控制不同的 Ajax 事件。

  • ifModified

    类型:Boolean 仅在服务器数据改变时获取新数据。默认值: false。

  • jsonp

    类型:String 在一个 jsonp 请求中重写回调函数的名字。

  • jsonpCallback

    类型:String 为 jsonp 请求指定一个回调函数名。

  • password

    类型:String 用于响应 HTTP 访问认证请求的密码

  • processData

    类型:Boolean 默认值: true。默认情况下,通过data选项传递进来的数据,如果是一个对象(技术上讲只要不是字符串),都会处理转化成一个查询字符串,以配合默认内容类型 “application/x-www-form-urlencoded”。

  • scriptCharset

    类型:String 只有当请求时 dataType 为 “jsonp” 或 “script”,并且 type 是 “GET” 才会用于强制修改 charset。通常只在本地和远程的内容编码不同时使用。

  • success

    类型:Function请求成功后的回调函数。参数:由服务器返回,并根据 dataType 参数进行处理后的数据;描述状态的字符串。这是一个 Ajax 事件。

  • traditional

    类型:Boolean 如果你想要用传统的方式来序列化数据,那么就设置为 true。请参考工具分类下面的 jQuery.param 方法。

  • timeout

    类型:Number 设置请求超时时间(毫秒)。此设置将覆盖全局设置。

  • type

    类型:String。请求方式 (“POST” 或 “GET”), 默认为 “GET”。

  • url

    类型:String 默认值: 当前页地址。发送请求的地址。

  • username

    类型:String 用于响应 HTTP 访问认证请求的用户名。

  • xhr

    类型:Function 需要返回一个 XMLHttpRequest 对象。


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
<%--
CDN
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
--%>
<script src="${pageContext.request.contextPath}/statics/js/jquery-3.6.0.min.js"></script>
<script>
function a1(){
$.post({
url:"${pageContext.request.contextPath}/a1",
data:{'name':$("#txtName").val()},
success:function (data,status) {
alert(data);
alert(status);
}
});
}
</script>
</head>
<body>

<%--失去焦点触发事件 发起一个请求--%>
用户名:<input type="text" id="txtName" onblur="a1()"/>

</body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
@Controller
public class AjaxController {
@RequestMapping("/a1")
public void ajax1(String name , HttpServletResponse response) throws IOException {
if ("admin".equals(name)){
response.getWriter().print("true");
}else{
response.getWriter().print("false");
}
}

}

$ is not defined:statis/js/jquery.js(与WEB-INF同级)文件未导出

1.在SpringMVC配置文件加入:

1
<mvc:default-servlet-handler/>

2.删除out文件夹,在pom.xml加入:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<!--静态资源导出-->
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</build>

AJAX数据回显

1.编写实体类

1
2
3
4
5
6
7
8
9
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private String name;
private int age;
private String sex;

}

2.编写Controller类

1
2
3
4
5
6
7
8
9
10
11
@RestController
public class AjaxController {
@RequestMapping("/a2")
public List<User> ajax2(){
List<User> list = new ArrayList<User>();
list.add(new User("Mike",13,"male"));
list.add(new User("Joe",12,"male"));
list.add(new User("Kevin",23,"male"));
return list;
}
}

3.编写前端JSP页面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<input type="button" id="btn" value="获取数据"/>
<table width="80%" align="center">
<tr>
<td>姓名</td>
<td>年龄</td>
<td>性别</td>
</tr>
<tbody id="content">
</tbody>
</table>

<script src="${pageContext.request.contextPath}/statics/js/jquery-3.6.0.min.js"></script>
<script>

$(function () {
$("#btn").click(function () {
$.post("${pageContext.request.contextPath}/a2",function (data) {
console.log(data)
var html="";
for (var 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>
</body>
</html>

AJAX密码验证

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@RestController
public class AjaxController {
@RequestMapping("/a3")
public String ajax3(String name,String pwd){
String msg = "";
/*模拟数据库中存在数据*/
if (name!=null){
if ("admin".equals(name)){
msg = "OK";
}else {
msg = "用户名输入错误";
}
}
if (pwd!=null){
if ("123456".equals(pwd)){
msg = "OK";
}else {
msg = "密码输入有误";
}
}
return msg; /*@RestController注解将msg转成json格式*/
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>ajax</title>
<script src="${pageContext.request.contextPath}/statics/js/jquery-3.6.0.min.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>

乱码问题参考JSON解决方案


获取Baidu接口Demo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>JSONP百度搜索</title>
<style>
#q{
width: 500px;
height: 30px;
border:1px solid #ddd;
line-height: 30px;
display: block;
margin: 0 auto;
padding: 0 10px;
font-size: 14px;
}
#ul{
width: 520px;
list-style: none;
margin: 0 auto;
padding: 0;
border:1px solid #ddd;
margin-top: -1px;
display: none;
}
#ul li{
line-height: 30px;
padding: 0 10px;
}
#ul li:hover{
background-color: #f60;
color: #fff;
}
</style>
<script>


<!--定义demo函数 (分析接口、数据)-->
function demo(data){
var Ul = document.getElementById('ul');
var html = '';
<!--如果搜索数据存在添加内容-->
if (data.s.length) {
<!--隐藏掉的ul显示出来-->
Ul.style.display = 'block';
<!--搜索到的数据循环追加到li-->
for(var i = 0;i<data.s.length;i++){
html += '<li>'+data.s[i]+'</li>';
}
<!--循环的li写入ul-->
Ul.innerHTML = html;
}
}


window.onload = function(){
<!--获取输入框和ul-->
var Q = document.getElementById('q');
var Ul = document.getElementById('ul');

<!--事件鼠标抬起时候-->
Q.onkeyup = function(){
<!--如果输入框不为空-->
if (this.value != '') {
<!--创建标签-->
var script = document.createElement('script');
<!--给定要跨域的地址 赋值给src-->
<!--请求的跨域的地址-->
script.src = 'https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd='+this.value+'&cb=demo';
<!--将组合好的带src的script标签追加到body里-->
document.body.appendChild(script);
}
}
}
</script>
</head>
<body>
<input type="text" id="q" />
<ul id="ul">
</ul>
</body>
</html>

拦截器

SpringMVC的拦截器(AOP)类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理。

过滤器

  • servlet规范
  • 在url-pattern中配置了/*之后,可以对所有要访问的资源进行拦截

拦截器

  • 拦截器属于SpringMVC框架
  • 拦截器拦截访问控制器方法,对于jsp/html/css/image/js不进行拦截

自定义拦截器

自定义拦截器必须实现HandlerInterceptor接口

1.编写拦截器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class MyInterceptor implements HandlerInterceptor {
/*
1.在请求的对应的控制器方法之前执行
2.如果返回true执行下一个拦截器,返回false则不执行下一个拦截器
*/
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
System.out.println("------------处理前------------");
return true;
}

/*在请求的对应的控制器方法执行之后执行*/
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
System.out.println("------------处理后------------");
}

/*在dispatcherServlet处理后执行*/
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
System.out.println("------------清理------------");
}
}

2.在SpringMVC配置文件中配置拦截器

1
2
3
4
5
6
7
8
9
10
<mvc:interceptors>
<mvc:interceptor>
<!--/** 包括路径及其子路径 -->
<!--/admin/* 拦截/admin/*, 但如/admin/*/*不会被拦截-->
<!--/admin/** 拦截/admin/下所有-->
<mvc:mapping path="/**"/>
<!--bean配置拦截器-->
<bean class="com.ling.controller.MyInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>

3.编写测试Controller类

1
2
3
4
5
6
7
8
9
10
/*测试拦截器的控制器*/
@Controller
public class InterceptorController {
@RequestMapping("/interceptor")
@ResponseBody
public String testFunction() {
System.out.println("执行控制器中的方法");
return "hello";
}
}

4.编写前端页面

1
<a href="${pageContext.request.contextPath}/interceptor">拦截器测试</a>

登录拦截

1.前端页面

  • index.jsp
1
2
3
4
5
6
7
8
9
10
11
12
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>$Title$</title>
</head>
<body>
<hr>
<%--登录--%>
<a href="${pageContext.request.contextPath}/user/gologin">登录</a>
<a href="${pageContext.request.contextPath}/user/main">首页</a>
</body>
</html>
  • main.jsp
1
2
3
4
5
6
7
8
9
10
11
12
13
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>首页</h1>
<span>${username}</span>
<p>
<a href="${pageContext.request.contextPath}/user/goOut">注销</a>
</p>
</body>
</html>
  • login.jsp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>

<h1>登录页面</h1>
<hr>
<!-- WEB-INF下所有的资源只能通过controller或者servlet访问-->
<body>
<form action="${pageContext.request.contextPath}/user/login">
用户名:<input type="text" name="username"> <br>
密码:<input type="password" name="password"> <br>
<input type="submit" value="提交">
</form>
</body>
</html>

2.编写Controller类以及Interceptor拦截类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
@Controller
@RequestMapping("/user")
public class LoginController {
@RequestMapping("/main")
public String main(){
return "main";
}
@RequestMapping("/gologin")
public String login(){
return "login";
}
@RequestMapping("/login")
public String login(HttpSession session, String username, String password, Model model){
/*将用户的信息存在session中*/
session.setAttribute("userLoginInfo",username);
model.addAttribute("username",username);
return "main";
}

@RequestMapping("/goOut")
public String loginout(HttpSession session){
session.removeAttribute("userLoginInfo");
return "redirect:/";
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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("login")){
return true;
}
/*判断是否登录*/
if(session.getAttribute("userLoginInfo")!=null){
return true;
}
request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request,response);
return false;

}
}

3.在SpringMVC配置文件中注册拦截器

1
2
3
4
5
6
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/user/**"/>
<bean class="com.ling.config.LoginInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>

文件上传和下载

1.为了能上传文件,需要将表单的method设置为POST,并将enctype设置为multipart/form-data。只有在这样的情况下,浏览器才会把用户选择的文件以二进制数据发送给服务器;

表单中的 enctype 属性:

  • application/x-www=form-urlencoded:默认方式,只处理表单域中的 value 属性值,采用这种编码方式的表单会将表单域中的值处理成 URL 编码方式。
  • multipart/form-data:以二进制流的方式来处理表单数据,会把文件域指定文件的内容也封装到请求参数中,不会对字符编码。
  • text/plain:除了把空格转换为 "+" 号外,其他字符都不做编码处理,这种方式适用直接通过表单发送邮件

2.一旦设置了enctype为multipart/form-data,浏览器即会采用二进制流的方式来处理表单数据,而对于文件上传的处理则涉及在服务器端解析原始的HTTP响应。在2003年,Apache Software Foundation发布了开源的Commons FileUpload组件,其很快成为Servlet/JSP程序员上传文件的最佳选择。

  • Servlet3.0规范已经提供方法来处理文件上传,但这种上传需要在Servlet中完成。
  • Spring MVC为文件上传提供了直接的支持,这种支持是用即插即用的MultipartResolver实现的。
  • Spring MVC使用Apache Commons FileUpload技术实现了一个MultipartResolver实现类:CommonsMultipartResolver。因此,SpringMVC的文件上传还需要依赖Apache Commons FileUpload的组件。
    • String getOriginalFilename():获取上传文件名
    • InputStream getInputStream():获取文件流
    • void transferTo(File dest):将上传文件保存到一个目录文件

1.添加依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
<!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</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>

2.配置multipartResolver

1
2
3
4
5
6
7
8
<!--文件上传配置-->
<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>

3.编写前端页面

1
2
3
4
<form action="${pageContext.request.contextPath}/upload" enctype="multipart/form-data" method="post">
<input type="file" name="file"/>
<input type="submit" value="upload">
</form>
1
<a href="${pageContext.request.contextPath}/download">点击下载</a>

4.编写Controller类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
@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";
}

@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";
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
@Controller
public class FileController {
@RequestMapping(value="/download")
public String downloads(HttpServletResponse response , HttpServletRequest request) throws Exception{
/*要下载的图片地址*/
String path = request.getServletContext().getRealPath("/upload");
String fileName = "1.jpg";

/*设置response 响应头*/
response.reset(); /*设置页面不缓存*/
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);
InputStream input=new FileInputStream(file);
OutputStream out = response.getOutputStream();

byte[] buff =new byte[1024];
int index=0;
while((index= input.read(buff))!= -1){
out.write(buff, 0, index);
out.flush();
}
out.close();
input.close();
return null;
}
}