5.3Java全栈开发前端+后端(全栈工程师进阶之路)-服务端框架-SpringMVC框架-相信我看这一篇足够

1.SpringMVC框架简介

1.1.框架简介

Spring MVC 是 Spring 提供给 Web 应用的框架设计。

Spring MVC 角色划分清晰,分工明细,并且和 Spring 框架无缝结合。作为当今业界最主流的 Web 开发框架,Spring MVC 已经成为当前javaWeb框架事实上的标准。

1.2.SpringMVC核心架构流程

springMVC核心架构的具体流程步骤如下:

  1. 首先用户发送请求——>DispatcherServlet(前端控制器),前端控制器收到请求后自己不进行处理,而是委托给其他的解析器进行处理,作为统一访问点,进行全局的流程控制;

  2. DispatcherServlet——>HandlerMapping, HandlerMapping将会把请求映射为HandlerExecutionChain对象(包含一个Handler处理器(页面控制器)对象、多个HandlerInterceptor拦截器)对象,通过这种策略模式,很容易添加新的映射策略;

  3. DispatcherServlet——>HandlerAdapter,HandlerAdapter将会把处理器包装为适配器,从而支持多种类型的处理器,即适配器设计模式的应用,从而很容易支持很多类型的处理器;

  4. HandlerAdapter——>处理器功能处理方法的调用,HandlerAdapter将会根据适配的结果调用真正的处理器的功能处理方法,完成功能处理;并返回一个ModelAndView对象(包含模型数据、逻辑视图名);

  5. ModelAndView的逻辑视图名——> ViewResolver, ViewResolver将把逻辑视图名解析为具体的View,通过这种策略模式,很容易更换其他视图技术;

  6. View——>渲染,View会根据传进来的Model模型数据进行渲染,此处的Model实际是一个Map数据结构,因此很容易支持其他视图技术;

  7. 返回控制权给DispatcherServlet,由DispatcherServlet返回响应给用户,到此一个流程结束。

1.3.前后端分离架构下的SpringMVC

上一节中,详细描述了SpringMVC的核心架构流程。 但是要注意:这是非前后端分离模式下的SpringMVC核心架构。

所以,我们会看到:在Handler处理器执行后,返回一个ModelAndView;也就是说:在非前后端分离模式下,视图层是由服务器端控制的。

那么,在前后端分离模式下,视图层要分离出去,成为一个独立工程;或者说:视图层不在由服务器端控制。 所以,在前后端分离模式下,SpringMVC的核心架构流程修改如下:

 

本教程中,讲解的都是在前后端分离模式下的SpringMVC

2.SpringMVC框架实例

SpringMVC框架的开发有两种方式:

  1. 配置文件方式

  2. 注解方式

本教程中,只讲解注解方式

2.1.创建Maven工程

注意:SpringMVC是Web工程,所以打包方式要选择 war 包。 

 

注意:Maven创建Web工程后,需要手动添加 WEB-INF 目录与 web.xml 配置文件。 

2.2.在pom.xml文件中添加依赖

<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 https://maven.apache.org/xsd/maven- 
4.0.0.xsd"> 
<modelVersion>4.0.0</modelVersion> 
<groupId>com.neusoft</groupId> 
<artifactId>smvc</artifactId> 
<version>0.0.1-SNAPSHOT</version> 
<packaging>war</packaging> 
<build> 
<plugins> 
<!-- 设置jdk版本 --> 
<plugin> 
<groupId>org.apache.maven.plugins</groupId> 
<artifactId>maven-compiler-plugin</artifactId> 
<configuration> 
<source>1.8</source> 
<target>1.8</target> 
<encoding>utf-8</encoding> 
</configuration> 
</plugin> 
</plugins> 
</build> 
<properties> 
<spring.version>5.3.20</spring.version> 
</properties> 
<dependencies> 
<!-- 此依赖会关联引用Spring中的所有基础jar包 --> 
<dependency> 
<groupId>org.springframework</groupId> 
<artifactId>spring-context</artifactId> 
<version>${spring.version}</version> 
</dependency> 
<!-- spring-webmvc会依赖spring-web --> 
<dependency> 
<groupId>org.springframework</groupId> 
<artifactId>spring-webmvc</artifactId> 
<version>${spring.version}</version> 
</dependency> 
</dependencies> 
</project>

2.3.配置SpringMVC前端控制器

在 web.xml 文件中配置 SpringMVC 前端控制器,也就是配置 DispatcherServlet 核心组件。

<?xml version="1.0" encoding="UTF-8"?> 
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xmlns="http://xmlns.jcp.org/xml/ns/javaee" 
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web
app_3_1.xsd" id="WebApp_ID" version="3.1"> 
<servlet> 
<servlet-name>springmvc</servlet-name> 
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> 
<!-- 也可不配置参数,默认加载 /WEB-INF/springmvc-servlet.xml --> 
<init-param> 
<param-name>contextConfigLocation</param-name> 
<param-value>classpath:springmvc-servlet.xml</param-value> 
</init-param> 
</servlet> 
<servlet-mapping> 
<servlet-name>springmvc</servlet-name> 
<url-pattern>/</url-pattern> 
</servlet-mapping> 
</web-app> 

2.4.创建Handler处理器

在 com.neusoft.springmvc.controller 包下创建 HelloController 处理器。

package com.neusoft.smvc.controller; 
import org.springframework.stereotype.Controller; 
import org.springframework.web.bind.annotation.RequestMapping; 
import org.springframework.web.bind.annotation.ResponseBody; 
@Controller 
public class HelloController { 
@ResponseBody 
@RequestMapping("/hello") 
public String hello() throws Exception { 
return "hello world!"; 
} 
}

@Controller:此注解声明在类上,表示此类是一个 Handler 处理器类,并被纳入到 Spring 容器中;

@ResponseBody:此注解可以声明在类上,或者方法上;表示处理器方法直接返回数据。

@RequestMapping:此注解可以声明在类上,或者方法上;表示将一个请求url映射给处理器方法。

2.5.创建SpringMVC配置文件

在resources文件夹下创建springmvc-servlet.xml 配置文件

<?xml version="1.0" encoding="UTF-8"?> 
<beans 
xmlns="http://www.springframework.org/schema/beans" 
xmlns:context="http://www.springframework.org/schema/context" 
xmlns:aop="http://www.springframework.org/schema/aop" 
xmlns:mvc="http://www.springframework.org/schema/mvc" 
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 
http://www.springframework.org/schema/context 
http://www.springframework.org/schema/context/spring-context.xsd 
http://www.springframework.org/schema/aop 
http://www.springframework.org/schema/aop/spring-aop.xsd 
http://www.springframework.org/schema/mvc 
http://www.springframework.org/schema/mvc/spring-mvc.xsd"> 
<!-- 
此标签能够自动加载注解的处理器映射和注解的处理器适配, 
而且还默认加载了很多其他方法。 比如:参数绑定到控制器参数、json转换解析器 
--> 
<mvc:annotation-driven /> 
<!-- 开启注解扫描,将包下带有@Controller注解的类纳入Spring容器中--> 
<context:component-scan base-package="com.neusoft.smvc.controller" /> 
</beans>

2.6.测试

将工程部署到Tomcat中,启动服务器,在浏览器地址栏中写入:http://localhost:8080/smvc/hello

2.7.相关注解详解

2.7.1.@ResponseBody注解

@responseBody注解的作用是将controller的方法返回的数据写入到response对象的body区,也就是直接将数据

写入到输出流中,效果等同于使用 response.getWriter() 输出流对象向前端返回数据。需要注意的是,在使用此注解之后,响应不会再走视图处理器。

  1. @responseBody 应用在处理器类上:此处理器类中的所有方法都直接返回数据。

  2. @responseBody 应用在处理器类的某个方法上:此处理器类中的某个方法直接返回数据。

2.7.2.@RequestMapping注解

用于建立请求URL和处理器方法之间的对应关系。

  1. @RequestMapping 应用在处理器类上: 设置请求URL的第一级访问目录。此处不写的话,就相当于应用的根目录。写的话需要以 / 开头。 它出现的目的是为了使我们的URL可以按照模块化管理。

@Controller 
@RequestMapping("/user") 
public class HelloController { 
@ResponseBody 
@RequestMapping("/hello") 
public String hello() throws Exception { 
return "hello world"; 
} 
}

上面处理器方法请求url应该这样写:http://localhost:8080/springmvc/user/hello

  1. @RequestMapping 应用在处理器类的某个方法上:请求URL的第二级访问目录。

  2. @RequestMapping注解中常用属性有:

      value:用于指定请求的URL。 method:用于指定请求的方式。

@ResponseBody 
@RequestMapping(value="/hello",method=RequestMethod.POST) 
public String hello() throws Exception { 
return "hello world"; 
}

如果使用 get 方式访问此处理器方法时(比如:在地址栏中输入url访问),就会出现异常。

2.7.3.@GetMapping与@PostMapping

@GetMapping是一个组合注解,是@RequestMapping(method = RequestMethod.GET)的缩写。

@PostMapping是一个组合注解,是@RequestMapping(method = RequestMethod.Post)的缩写。

3.处理器方法的参数与返回值

3.1.处理器方法参数

SpringMVC也是基于Spring的,所以可以直接给处理器方法注入参数,自动绑定默认支持的各种数据类型。 这些默认支持的数据类型,或者说可以注入的对象类型有:

  1. HttpServletRequest对象。

  2. HttpServletResponse对象。

  3. HttpSession对象。(注意:ServletContext不会注入。)

注意,注入上面的ServletAPI对象需要添加servlet-api依赖

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

4.简单数据类型。作用:获取客户端提交的单值参数。

public String hello(String userName,String password) throws Exception {}

注意:处理器方法的参数名必须与提交参数名一致。

测试:http://localhost:8080/springmvc/user/hello?userName=zhangsan&password=123

5.数组类型。 作用:获取客户端提交的多值参数

public String hello(Integer[] aihao) throws Exception {} 

注意:处理器方法的参数名必须与提交参数名一致。

测试:http://localhost:8080/springmvc/user/hello?aihao=1&aihao=2&aihao=3

 6.对象类型。 作用:获取客户端提交参数。

public String hello(User user) throws Exception {}

注意:处理器方法的参数名可以任意,但参数中的属性名必须与提交参数名一致。

测试:http://localhost:8080/springmvc/user/hello?userId=1&userName=zhangsan&password=123

3.2.使用@RequestParam匹配参数

获取客户端提交参数时,处理器的参数名必须与提交参数名一致。但如果处理器的参数名与提交参数名不一致时,可以使用@RequestParam注解来匹配参数。

public String hello(@RequestParam("username") String un, 
@RequestParam("password") String pw) throws Exception {} 

注意:@RequestParam的value值必须与提交参数名一致。

测试:http://localhost:8080/springmvc/user/hello?userName=zhangsan&password=123

3.3.前后端分离架构应用程序

3.3.1.跨域访问问题

在开发前后端分离架构应用程序中,有一个关键问题必须要解决,这就跨域访问问题。

当一个客户端访问服务器端时,如果客户端URL中的协议、IP、端口三者之间的任一个,与服务器端URL的协议、IP、端口不同时,即为跨域访问。

AJAX默认不允许跨域访问(为了安全),如何解决呢?通常有两种解决方案:

  1. 服务器端设置允许跨域访问; 比如:CORS(跨域资源共享)代理方式

  2. 前端通过代理进行跨域访问;比如:Vue-cli自带的跨域代理方式

在服务器端添加CORS过滤器:

package com.neusoft.smvc.filter; 
import java.io.IOException; 
import javax.servlet.Filter; 
import javax.servlet.FilterChain; 
import javax.servlet.FilterConfig; 
import javax.servlet.ServletException; 
import javax.servlet.ServletRequest; 
import javax.servlet.ServletResponse; 
import javax.servlet.annotation.WebFilter; 
import javax.servlet.http.HttpServletRequest; 
import javax.servlet.http.HttpServletResponse; 
@WebFilter("/*") 
public class CorsFilter implements Filter { 
@Override 
public void init(FilterConfig filterConfig) throws ServletException {} 
@Override 
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) 
throws IOException, ServletException { 
HttpServletRequest request = (HttpServletRequest)req; 
HttpServletResponse response = (HttpServletResponse)resp; 
//设置允许跨域
response.setHeader("Access-Control-Allow-Origin",request.getHeader("Origin")); 
//设置开启Cookie 
response.setHeader("Access-Control-Allow-Credentials", "true"); 
chain.doFilter(req, resp); 
} 
@Override 
public void destroy() {} 
}

3.3.2.前后端分离架构实例

get方式提交

前端:

<button onclick="hello()">提交</button> 
<script src="https://unpkg.com/axios/dist/axios.js"></script> 
<script> 
let user = { 
userId:1, 
userName:'zhangsan', 
password:'123' 
}; 
function hello() { 
axios.get('http://localhost:8080/smvc/user/hello',{params:user}) 
.then(response=>{ 
console.log(response.data); 
}).catch(error=>{ 
console.log(error); 
}); 
} 
</script>

服务器端:

public String hello(Integer userId,String userName,String password) throws Exception {}

post方式提交

前端

<button onclick="hello()">提交</button> 
<script src="https://unpkg.com/axios/dist/axios.js"></script> 
<script src="https://cdn.bootcss.com/qs/6.5.1/qs.min.js"></script> 
<script> 
let user = { 
userId:1, 
userName:'zhangsan',
password:'123' 
}; 
function hello() { 
axios.post('http://localhost:8080/smvc/user/hello',Qs.stringify(user)) 
.then(response=>{ 
console.log(response.data); 
}).catch(error=>{ 
console.log(error); 
}); 
} 
</script>

服务器端:

public String hello(User user) throws Exception {} 

3.4.处理器方法返回值

SpringMVC的处理器方法可以返回 ModelAndView ,也可以直接返回数据。 在前后端分离模式中,SpringMVC的处理器方法直接返回数据。所以,返回 ModelAndView 的情况不做讨论。

  1. 返回 String

上面实例中,SpringMVC的处理器方法就是直接返回String。

  1. 返回 json

首先,在 pom.xml 文件中添加 jackson 依赖:

<!-- jackson相关依赖 --> 
<dependency> 
<groupId>com.fasterxml.jackson.core</groupId> 
<artifactId>jackson-databind</artifactId> 
<version>2.9.0</version> 
</dependency>

服务器端代码:

//返回值设置为对象或者集合 
@ResponseBody 
@RequestMapping("/hello") 
public User hello(User user) throws Exception { 
System.out.println(user); 
return user; 
} 
/* 
@ResponseBody 
@RequestMapping("/hello") 
public List<User> hello(User user) throws Exception { 
List<User> list = new ArrayList<>(); 
list.add(user);
list.add(user); 
list.add(user); 
return list; 
} 
*/ 

前端代码:

axios.post('http://localhost:8080/smvc/user/hello',Qs.stringify(user)) 
.then(response=>{ 
console.log(response.data); 
}).catch(error=>{ 
console.log(error); 
}); 

注意:

  1. springmvc-servlet.xml 配置文件中必须要有 mvc:annotation-driven 标签配置。这里配置了json转换解析器。

  2. 只要 SpringMVC 的处理器返回值设置为对象,或者集合,那么就能返回 json 数据。

4.SpringMVC文件上传

4.1.添加文件上传jar包依赖

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

4.2.配置文件上传解析器

在springmvc-servlet.xml 配置文件中配置文件上传解析器。

<!--必须要有此id名 --> 
<bean id="multipartResolver" 
class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> 
<!--上传文件大小限制,单位:字节 --> 
<property name="maxUploadSize" value="5000000"></property> 
</bean>

4.3.创建上传文件处理器

package com.neusoft.smvc.controller; 
import java.io.File; 
import java.util.UUID; 
import javax.servlet.http.HttpServletRequest; 
import javax.servlet.http.HttpSession; 
import org.springframework.stereotype.Controller; 
import org.springframework.web.bind.annotation.RequestMapping; 
import org.springframework.web.bind.annotation.ResponseBody; 
import org.springframework.web.multipart.MultipartFile; 
@Controller 
public class UploadController { 
@ResponseBody 
@RequestMapping("/upload") 
// 必须要有MultipartFile类型参数。而且参数名必须与表单file控件名一致 
public String upload(MultipartFile myFile) { 
//上传图片存储目录 
String path = "d:/upload"; 
//获取文件名并使用UUID生成新文件名 
String fileName = myFile.getOriginalFilename(); 
String newFileName = UUID.randomUUID() + fileName.substring(fileName.lastIndexOf(".")); 
//在指定上传图片存储目录中创建新文件 
File targetFile = new File(path, newFileName); 
//如果找不到指定目录和文件,就新创建此目录和文件 
if (!targetFile.exists()) { 
targetFile.mkdirs(); 
} 
//将文件写入硬盘(myFile在内存中) 
try { 
myFile.transferTo(targetFile); 
} catch (Exception e) { 
e.printStackTrace(); 
} 
return "ok"; 
} 
}

4.4.客户端表单提交

<form action="http://localhost:8080/smvc/upload" enctype="multipart/form-data" method="post"> 
<input type="file" name="myFile"><br> 
<input type="submit" value="上传"> 
</form> 

注意:

1.enctype:设置表单提交时发送服务器数据的编码方式。

默认情况,这个编码格式是application/x-www-form-urlencoded(标准键值对格式),不能用于文件

上传;只有使用了multipart/form-data,才能上传二进制数据;

2.method:必须为post方式提交。

5.SpringMVC拦截器

早期MVC框架将一些通用操作写死在核心控制器中,致使框架灵活性不足、可扩展性降低。

Spring将预处理与后处理功能放到多个拦截器中实现,拦截器可自由选择和组合,增强了灵活性,有利于系统的解

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

5.1.创建SpringMVC拦截器

创建 SpringMVC 拦截器,只需要实现 HandlerInterceptor 接口即可。 接口中有三个方法需要实现:

  1. preHandle:该方法在 controller 执行前执行,可以实现对数据的预处理。如果方法返回 true ,则继续调用下一个资源。否则不在继续调用。

  2. postHandle:该方法在处理器执行后,生成视图前执行。这里有机会修改视图层数据。

  3. afterCompletion:最后执行,通常用于记录日志,释放资源,处理异常。

package com.neusoft.springmvc.interceptor; 
import javax.servlet.http.HttpServletRequest; 
import javax.servlet.http.HttpServletResponse; 
import org.springframework.web.servlet.HandlerInterceptor; 
import org.springframework.web.servlet.ModelAndView; 
public class CharSetInterceptor implements HandlerInterceptor{ 
@Override 
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object
handler) throws Exception { 
System.out.println("在到达处理器之前做前置工作"); 
return true; 
} 
@Override 
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object 
handler,ModelAndView modelAndView) throws Exception {} 
@Override 
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object 
handler, Exception ex)throws Exception {} 
}

5.2.配置SpringMVC拦截器

在springmvc-servlet.xml 配置文件中配置 SpringMVC 拦截器。

<!-- 可以配置多个拦截器 --> 
<mvc:interceptors> 
<mvc:interceptor> 
<mvc:mapping path="/**" /> 
<bean class="com.neusoft.springmvc.interceptor.CharSetInterceptor" /> 
</mvc:interceptor> 
</mvc:interceptors>

6.RESTful接口规范

6.1.什么是RESTful接口规范

在前后端分离架构的理念中认为:服务器端的任务就是给前端提供数据的。所以,服务器端就需要给前端提供WebAPI接口,用于前端访问。而Web API接口的制定是需要遵守规范的。

RESTful:是一种定义Web API接口的规范。具体来说:RESTful规范要求我们:

  1. 对url进行规范,写出符合RESTful格式的url。优雅RESTful风格的资源URL不希望带 ?或 & 等后缀

  2. 指定请求资源格式。

也就是说:在RESTful架构中,每个URI代表一种资源,客户端通过四个HTTP方法(四个动词),对服务器端

资源进行操作:

GET用来获取资源;

POST用来新建资源(也可以用于更新资源);

PUT用来更新资源;

DELETE用来删除资源;

6.2.使用RESTful接口规范

1.客户端提交方式:

http://localhost:8080/springmvc/hello/zhangsan/123 

2.处理器接收参数方式:

@ResponseBody 
@RequestMapping("/hello/{userName}/{password}") 
public String hello(@PathVariable("userName") String userName,@PathVariable("password") 
String password) throws Exception { 
System.out.println(userName+","+password); 
return "hello world!"; 
}

  • 22
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
这个网上书城项目采用了当前最流行的框架spring-springmvc-mybatis设计。这个项目旨在提供一个方便、快捷的购书平台,用户可以通过该平台浏览、搜索并购买自己喜欢的图书。 在这个项目中,我们使用了Spring作为项目的核心框架,它提供了依赖注入和面向切面编程等功能,使得项目的开发更加简洁和易于维护。Spring MVC作为项目的Web框架,负责将用户的请求路由到对应的Controller,并负责视图的渲染和返回。而MyBatis则是作为持久层框架,将数据库的操作和Java代码的实现解耦,提供了灵活的SQL映射和缓存机制。 在这个网上书城项目中,我们设计了一套完整的功能模块:用户管理模块、图书管理模块、订单管理模块等。用户可以通过注册、登录等功能来进行用户管理,并可以在平台上对图书进行购买、收藏等操作。同时,平台还提供了搜索功能,用户可以根据图书的名称、作者等进行快速查找。 这个项目的设计更加便于扩展和维护,使用了分层架构,将业务逻辑、持久层和展示层进行了有效的分离。同时,也采用了面向接口编程的思想,降低了模块之间的耦合度,提高了代码的复用性和可测试性。 总之,这个网上书城项目基于spring-springmvc-mybatis框架的设计,充分利用了各自的优势,提供了一个高效、稳定和易于维护的购书平台。期望能为用户提供良好的购书体验,并为图书销售行业的发展做出贡献。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

明裕学长

打赏私我进交流群

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值