目录
1、MVC简介
1.1、JSP+JavaBean模式
1.2、Servlet+JSP+JavaBean模式
1.3、MVC优缺点
2、SpringMVC
2.1、什么是SpringMVC:
2.2、优点:
3、第一个SpringMVC程序
3.1、项目结构
3.2、搭建环境
3.3、SpringMVC配置
3.4、底层原理分析
4、使用注解开发SpringMVC
4.1、项目结构:
4.2、项目步骤
5、@RequestMapping详解
5.1、解析源码
5.2、简单实例
5.3、method 属性
5.3、使用RestFul风格
6、乱码处理
7、JSON
7.1、什么是JSON
7.2、JSON语法规则
7.3、JSON与JS关系
8、Jackson
8.1、实例
8.2、自定义ObjectMapper获取工具包
8.3、项目结构
MVC 设计模式一般指 MVC 框架,M(Model)指数据模型层,V(View)指视图层,C(Controller)指控制层。使用 MVC 的目的是将 M 和 V 的实现代码分离,使同一个程序可以有不同的表现形式。其中,View 的定义比较清晰,就是用户界面。
官方配置文件:Web on Servlet Stack
View(视图):jsp
负责格式化数据并把它们呈现给用户,包括数据展示、用户交互、数据验证、界面设计等功能。
Controller(控制器):servlet
负责接收并转发请求,对请求进行处理后,指定视图并将结果发送给客户端。
Model(模型):dao,service,JavaBean
模型对象拥有最多的处理任务,是应用程序的主体部分,负责数据逻辑(业务规则)的处理和实现数据操作即在数据库中存取数据。
SUN公司推出JSP技术后,同时也推荐了两种web应用程序的开发模式,一种是JSP+JavaBean模式,一种是Servlet+JSP+JavaBean模式。
y优点:适合开发业务逻辑不太复杂的web应用程序,这种模式下,JavaBean用于封装业务数据,JSP即负责处理用户请求,又显示数据。
缺点:JSP+JavaBean 模式中 JSP 身兼数职,既要负责视图层的数据显示,又要负责业务流程的控制,结构较为混乱,并且也不是我们所希望的松耦合架构模式,所以当业务流程复杂的时候并不推荐使用。
Servlet+JSP+JavaBean 中 Servlet 用于处理用户请求,JSP 用于数据显示,JavaBean 用于数据封装,适合复杂的 Web 程序。
相比 JSP+JavaBean 模式来说,Servlet+JSP+JavaBean 模式将控制层单独划分出来负责业务流程的控制,接收请求,创建所需的 JavaBean 实例,并将处理后的数据返回视图层(JSP)进行界面数据展示。
Servlet+JSP+JavaBean 模式的结构清晰,是一个松耦合架构模式,一般情况下,建议使用该模式。
1.用户发送请求
2.Servlet接收请求,并调用对应的业务逻辑方法处理
3.业务处理完后,返回更新后的数据给servlet
4.servlet转向给jsp,由jsp渲染页面
5.响应给用户更新后的页面
优点:
多视图共享一个模型,大大提高了代码的可重用性
MVC 三个模块相互独立,松耦合架构
控制器提高了应用程序的灵活性和可配置性
有利于软件工程化管理
总的来说,可以通过 MVC 设计模式打造出一个松耦合+高可重用性+高可适用性的完美架构。
缺点:
原理复杂
增加了系统结构和实现的复杂性
视图对模型数据的低效率访问
MVC 并不适合小型甚至中型规模的项目,花费大量时间将 MVC 应用到规模并不是很大的应用程序,通常得不偿失,所以对于 MVC 设计模式的使用要根据具体的应用场景来决定。
Spring MVC 是 Spring 提供的一个基于 MVC 设计模式的轻量级 Web 开发框架,本质上相当于 Servlet。
SpringMVC是由Servlet+JSP+JavaBean实现的。
Spring 框架提供了构建 Web应用程序的全功能 MVC 模块。使用 Spring 可插入的 MVC 架构,从而在使用Spring进行WEB开发时,可以选择使用Spring的Spring MVC框架或集成其他MVC开发框架
它是一个典型的教科书式的mvc构架,而不像struts等都是变种或者不是完全基于mvc系统的框架,对于初学者或者想了解mvc的人来说我觉得 spring是最好的,它的实现就是教科书!第二它和tapestry一样是一个纯正的servlet系统,这也是它和tapestry相比 struts所具有的优势。而且框架本身有代码,看起来容易理解。
在 Spring MVC 框架中,Controller 替换 Servlet 来担负控制器的职责,用于接收请求,调用相应的 Model 进行处理,处理器完成业务处理后返回处理结果。Controller 调用相应的 View 并对处理结果进行视图渲染,最终客户端得到响应信息。
易于同其它View框架(Tiles等)无缝集成,采用IOC便于测试。
清晰地角色划分,Spring MVC 在 Model、View 和 Controller 方面提供了一个非常清晰的角色划分,这 3 个方面真正是各司其职,各负其责。
灵活的配置功能,可以把类当作 Bean 通过 XML 进行配置。
提供了大量的控制器接口和实现类,开发者可以使用 Spring 提供的控制器实现类,也可以自己实现控制器接口。
面向接口编程
Spring MVC 框架采用松耦合可插拔的组件结构,具有高度可配置性,比起其它 MVC 框架更具有扩展性和灵活性。
真正做到与 View 层的实现无关。它不会强制开发者使用 JSP,可以根据项目需求使用 Velocity、FreeMarker 等技术。
1.创建父工程SpringMVC并删除src文件
2.建立一个SpringMVC-01子项目,添加Web app支持
右键子项目-->Add Frameworks Support-->Web Application-->ok创建成功
3.导入SpringMVC的jar依赖
Spring MVC 依赖 JAR 文件包括 Spring 的核心 JAR 包和 commons-logging 的 JAR 包。
javax.servlet
javax.servlet-api
3.1.0
javax.servlet.jsp
jsp-api
2.2
org.springframework
spring-web
5.2.3.RELEASE
org.springframework
spring-webmvc
5.2.3.RELEASE
org.springframework
spring-context
5.2.3.RELEASE
org.springframework
spring-test
5.2.3.RELEASE
org.springframework
spring-jdbc
5.2.3.RELEASE
com.github.stefanbirkner
system-rules
1.16.1
test
org.aspectj
aspectjweaver
1.8.9
Spring MVC 是基于 Servlet 的,DispatcherServlet 是整个 Spring MVC 框架的核心,主要负责截获请求并将其分派给相应的处理器处理。所以配置 Spring MVC,首先要定义 DispatcherServlet。跟所有 Servlet 一样,用户必须在 web.xml 中进行配置。
1.注册DispatcherServlet
在web.xml中部署DispatcherServlet:
springMVC
springmvc
org.springframework.web.servlet.DispatcherServlet
contextConfigLocation
classpath:springmvc-servlet.xml
1
springmvc
/
2.创建Spring MVC配置文件(springmvc-servlet.xml)
文件名格式:【servletname】-servlet.xml
3.配置文件中添加处理映射器
4.配置文件中添加处理器适配器
5.配置文件中添加视图解析器
6.编写要操作的业务Controller
有两种方法:1.实现Controller接口;2.增加注解
需要返回一个ModelAndview,封装数据和要跳转的视图
public class FirstController implements Controller {
@Override
public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
//ModelAndView 模型和视图
ModelAndView mv = new ModelAndView();
//封装对象,放在ModelAndView中
mv.addObject("msg","Hello SpringMVC");
//封装要跳转的视图,放在ModelAndView中
mv.setViewName("hello");
return mv;
}
}
7.创建视图
在WEB-INF下添加一个hello.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
Title
${msg}
8.在springmvc-servlet.xml容器中注册bean
然后就可以运行程序了。
注意:如果遇到404的错误
代码没错的前提下,可能是:
1.查看控制台输出,看是不是却是jar包
2.jar包存在,显示无法输出,则在idea项目发布中,添加lib依赖
然后选择里面所有的包,导进去。
3.重启Tomcat
宏观视图:
微观视图:
流程解析:
1.DispatcherServlet是前置控制器,是整个SpringMVC的控制中心。用户发送请求,DispatcherServlet接收并拦截请求
假设请求的URL为:http://localhost:8080/SpringMVC_01_war_exploded/hello
url将会被分为三部分
http://localhost:8080 服务器域名
/SpringMVC_01_war_exploded 部署在服务器上的站点
/hello 控制器
请求位于服务器http://localhost:8080上的/站点的hello控制器
2.HandlerMapping为处理器映射。DispatcherServlet调用HandlerMapping,HandlerMapping根据请求url查找Handler。
3.HandlerExecution表示具体的Handler,其主要作用是根据url查找控制器,如上url被查找控制器为:hello。
4.HandlerExecution将解析后的信息传递给DispatcherServlet,如解析控制器映射等。
5.HandlerAdapter表示处理器适配器,其按照特定的规则去执行Handler。
6.Handler让具体的Controller执行。
7.Controller将具体的执行信息返回给HandlerAdapter,如ModelAndView。
8.HandlerAdapter将视图逻辑名或模型传递给DispatcherServlet。
9.DispatcherServlet调用视图解析器(ViewResolver)来解析HandlerAdapter传递的逻辑视图名。
10.视图解析器将解析的逻辑视图名传给DispatcherServlet。
11.DispatcherServlet根据视图解析器解析的视图结果,调用具体的视图。
12.最终视图呈现给用户。
本解析参考自:狂神说SpringMVC笔记_liufengxian3399的博客-CSDN博客
创建子项目SpringMVC-02-annotation
添加SpringMvc需要的依赖(前面有)
主要有:Spring框架核心库、SpringMVC、servlet、JSTL等
配置web.xml
web.xml需要最新版的 4.0
注册DispatcherServlet
关联SpringMVC的配置文件---->【servletname】-servlet.xml
启动级别为1
映射路径为/ 【注意:不要用/*,会遇到404报错】
springMVC
springmvc
org.springframework.web.servlet.DispatcherServlet
contextConfigLocation
classpath:springmvc-servlet.xml
1
springmvc
/
添加SpringMVC配置文件(springmvc-servlet.xml)
使用context:component-scan:扫描指定包文件,让指定包下的注解生效
default-servlet-handler:静态资源过滤
annotation-driven:MVC注解驱动,相当于HandlerMapping和HandlerAdapter
配置视图解析器
注意:从前缀可以看到,我是把视图存放在了/WEB-INF、目录下,这样是private的,客户端是访问不到的,如果是直接存放在WEN-INF中的话,是公共的,客户端是可以访问到的。
创建controller
编写java控制类:通过上面的base-package="com.wen.controller"可以看出,我的controller类是在=在com.wen.controller下的
@Controller
public class SecondController {
//访问地址:http://localhost:8080/项目名/hello
@RequestMapping("/hello")
public String hello(Model model){
//向模型中添加属性msg与其值,返回到jsp中
model.addAttribute("msg","Hello Second SpringMVC");
//返回给视图解析器一个字符串hello,然后通过前缀和后缀的拼接,成为:/WEB-INF/jsp/hello.jsp
return "hello";
}
}
Controller注解
@Controller注解用于声明某类的实例是一个控制器,能够让SpringIOC容器初始化时自动扫描到
RequestMapping注解
一个控制器内有多个处理请求方法,如增、删、改、查等,每个方法都负责不同的请求操作,@RequestMapping就是负责将请求映射到对应的控制器方法上。
在基于注解的控制器类中可以为每个请求编写对应的处理方法。使用 @RequestMapping 注解将请求与处理方法一 一对应即可。
@RequestMapping注解可用在类或方法上
用在类上:
@Controller
@RequestMapping("SecondController")
public class SecondController {
@RequestMapping("/hello")
public String hello(Model model){
model.addAttribute("msg","Hello Second SpringMVC");
return "hello";
}
}
他的请求路径为:http://localhost:8080/02/SecondController/hello
用在方法上:
@Controller
public class SecondController {
@RequestMapping("/hello")
public String hello(Model model){
model.addAttribute("msg","Hello Second SpringMVC");
return "hello";
}
}
他的请求路径为:http://localhost:8080/02/hello
创建视图层
前面讲过,视图层是建在WEB-INF下的 ,在WEB-INF下建一个jsp包,里面建一个hello.jsp文件。
注意:视图是可以直接从Controller里提取数据,通过EL表示(${})去除model中存放的值或对象。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
Title
${msg}
配置tomcat运行即可
注意事项:可能会遇到404,前面讲过第一个SpringMVC中讲过,要先去看这个项目里有没有lib文件,没有的话创建一个然后把jar包全导进去。
在Spring MVC 中使用 @RequestMapping 来映射请求,也就是通过它来指定控制器可以处理哪些URL请求,相当于Servlet中在web.xml中配置
RequestMapping可用于类或方法上。用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。
@Target({ElementType.TYPE, ElementType.METHOD})
@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 {};
}
@Target({ElementType.TYPE, ElementType.METHOD})
@Target有两个属性,分别为ElementType.TYPE和ElementType.METHOD,意思是可以在方法和类的声明中使用。
String name() default ""
指定请求路径的地址
@AliasFor("path")、@AliasFor("value")
指定请求路径的地址,其中path和value互为别名,@AliasFor是为了让被注解的能互相使用
RequestMethod[] method() default {}
指定请求方式,是一个RequestMethod数组,可以配置多个方法
String[] params() default {}
指定参数类型
String[] headers() default {}
指定请求的请求头
String[] consumes() default {}
指定数据请求的格式
String[] produces() default {}
指定返回的内容类型
1、此实验的环境为使用注解开发的环境(主要是懒)SpringMVC-02-annotation
2、创建RequestMappingTest1类
@Controller
public class RequestMappingTest1 {
//@RequestMapping 中的 value 和 path 属性(这两个属性作用相同,可以互换,如果仅有这一个属性,则可以省略,下面两个例子均采用省略的方式)
@RequestMapping(value = "/add")
public String test1(int a, int b, Model model){
int x = a+b;
model.addAttribute("msg","结果为:" + x);
return "test1";
}
}
3、创建对应的test1.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
Title
${msg}
4、运行程序,输入对应值
http://localhost:8080/02/add?a=3&b=6
这个是默认的输入方式
@RequestMapping 中的 method 主要用来定义接收浏览器发来的何种请求。在Spring中,使用枚举类
public enum RequestMethod {
GET,
HEAD,
POST,
PUT,
PATCH,
DELETE,
OPTIONS,
TRACE;
private RequestMethod() {
}
}
通过method=RequestMethod.GET指定test1()方法仅使用GET方式发送请求
@Controller
public class RequestMappingTest1 {
//@RequestMapping 中的 value 和 path 属性(这两个属性作用相同,可以互换,如果仅有这一个属性,则可以省略,下面两个例子均采用省略的方式)
@RequestMapping(value = "/add",method = RequestMethod.GET)
public String test1(int a, int b, Model model){
int x = a+b;
model.addAttribute("msg","结果为:" + x);
return "test1";
}
}
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
Title
可以看到,put.jsp上传的为post方法,而接受的却是get方法,会导致无法匹配
其他方法同理。
所有地址栏请求默认都会是HTTP GET类型的
方法级别的注解变体有:
@GetMapping
@PostMapping
@PutMapping
@DeleteMapping
@PatchMapping
他们都是一个组合注解,比如:
@GetMapping就相当于@RequestMapping(method = RequestMethod.GET)的一个快捷方式。极为便利!
在URL中,会有一些不同的写法风格
传统方式操作资源
/*
http://127.0.0.1/item/queryUser.action?id=1 查询,GET
http://127.0.0.1/item/saveUser.action 新增,POST
http://127.0.0.1/item/updateUser.action 更新,POST
http://127.0.0.1/item/deleteUser.action?id=1 删除,GET或POST
*/
使用RestFul操作资源
/*
【GET】 /users # 查询用户信息列表
【GET】 /users/01 # 查看某个用户信息
【POST】 /users # 新建用户信息
【PUT】 /users/01 # 更新用户信息(全部字段)
【PATCH】 /users/01 # 更新用户信息(部分字段)
【DELETE】 /users/01 # 删除用户信息
*/
案例:
@Controller
public class RequestMappingTest1 {
//@RequestMapping 中的 value 和 path 属性(这两个属性作用相同,可以互换,如果仅有这一个属性,则可以省略,下面两个例子均采用省略的方式)
@GetMapping("/add/{a}/{b}")
public String test1(@PathVariable int a, @PathVariable int b, Model model){
int x = a+b;
model.addAttribute("msg","结果为:" + x);
return "test1";
}
}
在传输数据时会有中文乱码现象,解决办法:
自定义过滤器
使用SpringMVC自带的过滤器
自定义过滤器这里就不说了,这里主要讲SpringMVC里的,只需配置web.xml即可:
encoding
org.springframework.web.filter.CharacterEncodingFilter
encoding
utf-8
encoding
/*
注意,
JSON(JavaScript Object Notation, JS 对象简谱) 是一种轻量级的数据交换格式。
它基于 ECMAScript(欧洲计算机协会制定的js规范)的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据。
简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。
易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率。
任何JavaScript支持的类型都可以通过JSON来表示,例如字符串、数字、对象、数组等。
方括号保存的是数组
花括号保存的是对象
对象则由键值对来表示,数据之间用逗号分隔
很多人搞不清楚 JSON 和 JS 对象的关系,甚至连谁是谁都不清楚。其实,可以这么理解:
JSON 是 JS 对象的字符串表示法,它使用文本表示一个 JS 对象的信息,本质是一个字符串。
//编写一个JavaScript对象
var user = {
name : "张三",
age : 21,
sex : "男"
};
console.log(user);
通过stringify将js对象转换为json对象
//将js对象转换为json对象
var json = JSON.stringify(user);
console.log(json);
可以看出js声明的是一个对象,通过stringify转换为json后就变为了一个字符串。
通过parse将json对象转换为JavaScript对象
//将json对象转换为JavaScript对象
var js = JSON.parse(json);
console.log(js);
我们需要通让ava将数据通过json输出到前端,可以通过Jackson来实现这个操作。
优点:
Jackson 是当前用的比较广泛的,用来序列化和反序列化 json 的 Java 的开源框架
Jackson 所依赖的 jar 包较少 ,简单易用
与其他 Java 的 json 的框架 Gson 等相比, Jackson 解析大的 json 文件速度比较快
Jackson 运行时占用内存比较低,性能比较好
Jackson 有灵活的 API,可以很容易进行扩展和定制。
Jackson的核心模块由三部分组成
核心包:jackson-core,提供基于"流模式"解析的相关 API,它包括 JsonPaser 和 JsonGenerator。 Jackson 内部实现正是通过高性能的流模式 API 的 JsonGenerator 和 JsonParser 来生成和解析 json
注解包:jackson-annotations,提供标准注解功能
数据绑定包:jackson-databind , 提供基于"对象绑定" 解析的相关 API ( ObjectMapper ) 和"树模型" 解析的相关 API (JsonNode);基于"对象绑定" 解析的 API 和"树模型"解析的 API 依赖基于"流模式"解析的 API
1、在pom.xml中导入Jackson的依赖
com.mastfrog
jackson
2.7.3
2、配置web.xml
springMVC
springmvc
org.springframework.web.servlet.DispatcherServlet
contextConfigLocation
classpath:springmvc-servlet.xml
1
springmvc
/
encoding
org.springframework.web.filter.CharacterEncodingFilter
encoding
utf-8
encoding
/*
3、在resources下配置springmvc-servlet.xml
4、编写实体类User,目的:将User里面的信息输出给前端页面
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private String name;
private int age;
private String sex;
}
5、创建UserController类实现方法
@Controller
public class UserController {
@RequestMapping("/json1")
@ResponseBody //通过这个注解,不会走视图解析器,会直接返回一个字符串,也可以直接在类上使用@RestController,替换掉@Controller和@ResponseBody ,表明这个类下的所有方法都不走视图解析器
public String json1() throws JsonProcessingException {
//Jackson
ObjectMapper mapper = new ObjectMapper();
//创建一个对象
User user = new User("张三", 21, "男");
String str = mapper.writeValueAsString(user);
return str;
}
}
返回结果:
{"name":"??","age":21,"sex":"?"}
6、解决乱码问题
手动解决
@RequestMapping(value = "/json1",params = "application/json;charset=utf-8")
SpringMVC配置统一指定:在SpringMVC的配置文件上添加一段消息StringHttpMessageConverter转换配置
如果每次传输数据都要去new一个ObjectMapper会很麻烦,所有创建一个工具包,自动new
1、创建一个工具包类
public class JsonUtil {
//实现代码的复用
public static String getJson(Object obj) {
return getJson(obj,"yyy-MM-dd HH:mm:ss"); //自己标准化的时间格式
}
public static String getJson(Object obj,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(obj);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return null;
}
}
2、调用工具包里的方法获取时间
@RequestMapping(value = "/json3")
//@ResponseBody //通过这个注解,不会走视图解析器,会直接返回一个字符串
public String json3() throws JsonProcessingException {
Date date = new Date();
return JsonUtil.getJson(date);
}
结果
"2021-12-02 01:15:51"
3、调用工具包里的方法,输出一个list
@RequestMapping(value = "/json2")
//@ResponseBody //通过这个注解,不会走视图解析器,会直接返回一个字符串
public String json2() throws JsonProcessingException {
//创建一个对象
List userList = new ArrayList();
User user1 = new User("老1", 21, "男");
User user2 = new User("老2", 21, "男");
User user3 = new User("老3", 21, "男");
userList.add(user1);
userList.add(user2);
userList.add(user3);
return JsonUtil.getJson(userList);
}
结果
[{"name":"老1","age":21,"sex":"男"},{"name":"老2","age":21,"sex":"男"},{"name":"老3","age":21,"sex":"男"}]