一、SpringMVC
1、MVC
M:Model,模型层,指工程中的JavaBean,作用是处理数据
JavaBean分为两类:
一类称为实体类Bean:专门存储业务数据的,如 Student、User 等
一类称为业务处理 Bean:指 Service 或 Dao 对象,专门用于处理业务逻辑和数据访问。
V:View,视图层,指工程中的html或jsp等页面,作用是与用户进行交互,展示数据
C:Controller,控制层,指工程中的servlet,作用是接收请求和响应浏览器
MVC的工作流程: 用户通过视图层发送请求到服务器,在服务器中请求被Controller接收,Controller调用相应的Model层处理请求,处理完毕将结果返回到Controller,Controller再根据请求处理的结果找到相应的View视图,渲染数据后最终响应给浏览器
2、SpringMVC概念
SpringMVC是spring框架的一个模块,springmvc和spring无需通过中间整合层进行整合。是一个WEB框架,基于MVC的理念而设计,是目前最主流的MVC框架之一。MVC的三个核心部件分别是:Model(模型)、View(视图)、Controller(控制器)。SpringMVC是Spring框架的一个模块,SpringMVC和Spring无需通过中间整合层进行整合。
SpringMVC3.0之后的版本超越了Struts2,成为最优秀的web框架。
SpringMVC通过MVC注解,让POJO成为处理请求的控制器,而且它不需要实现任何额外的接口。
SpringMVC支持REST风格的URL请求。
SpringMVC和其他MVC框架相比,具有更高的灵活性和可扩展性。
3、原理
客户端(浏览器)发送请求,直接请求到DispatcherServlet。
DispatcherServlet根据请求信息调用HandlerMapping,解析请求对应的Handler。
解析到对应的Handler后,开始由HandlerAdapter适配器处理。
HandlerAdapter会根据Handler来调用真正的处理器开处理请求,并处理相应的业务逻辑。
处理器处理完业务后,会返回一个ModelAndView对象,Model是返回的数据对象,View是个逻辑上的View。
ViewResolver会根据逻辑View查找实际的View。
DispaterServlet把返回的Model传给View。
通过View返回给请求者(浏览器)
4、优点
利用一个Controller类, 完成某项业务的全部调用
简化了配置
参数获取非常灵活
5、组件
前端控制器
DispatcherServlet:Spring提供的前端控制器,所有的请求都有经过它来统一分发。在DispatcherServlet将请求分发给Spring Controller之前,需要借助于Spring提供的HandlerMapping定位到具体的Controller。
处理器映射器
HandlerMapping:它的作用是请求派发,负责请求和控制器建立对应的关系。它是由 DispatcherServlet 调用,DispatcherServlet 会从容器中取出所有 HandlerMapping 实例并遍历,让 HandlerMapping 实例根据自己实现类的方式去尝试查找 Handler。也就是说,DispatcherServlet要将一个请求交给哪个特定的Controller,它需要咨询一个Bean,这个Bean的名字为“HandlerMapping”。
控制器
Controller:负责处理由DispatcherServlet 分发的请求,它把用户请求的数据经过业务处理层处理之后封装成一个Model ,然后再把该Model 返回给对应的View 进行展示。
封装数据信息和视图信息的模型
ModelAndView:使用ModelAndView类用来存储处理完后的结果数据,以及显示该数据的视图。从名字上看ModelAndView中的Model代表模型,View代表视图,这个名字就很好地解释了该类的作用。业务处理器调用模型层处理完用户请求后,把结果数据存储在该类的model属性中,把要返回的视图信息存储在该类的view属性中,然后让该ModelAndView返回该Spring MVC框架。框架通过调用配置文件中定义的视图解析器,对该对象进行解析,最后把结果数据显示在指定的页面上。
视图解析器
ViewResolver 的主要作用是把一个逻辑上的视图名称解析为一个真正的视图。
6、三层架构
dao->数据层
service -> 业务实现
web -> web 接口
或者
common—>公共方法,公共类,工具类,只有关键地方加日志
dao->数据层,不加日志
domain->实体类,不加日志
rpc->调用接口,出入参加日志
sdk-> 给外部提供sdk,例如对外接口,只是提供接口定义,该层没有业务逻辑,真实的sdk逻辑实现是在service层,不加日志
service -> 业务实现逻辑,单元测试进行层,日志接入:关键地方可以加, 实现sdk层的接口方法出入参加日志
web -> web 接口,对外提供http 接口,一般都有逻辑,http 是直接对 c的,看到的ip 是c端用户的,出入参加日志
(1)、service层
业务层,用来实现业务逻辑。能调用dao层或者service层,返回数据对象DO或者业务对象BO,BO通常由DO转化、整合而来,可以包含多个DO的属性,也可以是只包含一个DO的部分属性。通常为了简便,如果无需转化,service也可以直接返回DO。外部调用(HTTP、RPC)方法也在这一层,对于外部调用来说,service一般会将外部调用返回的DTO转化为BO。是专注业务逻辑,对于其中需要的数据库操作,都通过Dao层去实现。主要去负责一些业务处理,比如取得连接、关闭数据库连接、事务回滚,一些复杂的逻辑业务处理就放到service层。
(2)、DAO层
负责访问数据库进行数据的操作,取得结果集,之后将结果集中的数据取出封装到VO类对象之后返回给service层。数据层,直接进行数据库的读写操作,返回数据对象DO,DO与数据库表一一对应。Dao的作用是封装对数据库的访问:增删改查,不涉及业务逻辑,只是达到按某个条件获得指定数据的要求。
在实际开发中dao层要先定义出自己的操作标准即标准接口,就是为了解耦合。
(3)、Cotroller层
控制层,主要的功能是处理用户发送的请求。主要处理外部请求。调用service层,将service层返回的BO/DO转化为DTO/VO并封装成统一返回对象返回给调用方。如果返回数据用于前端模版渲染则返回VO,否则一般返回DTO。不论是DTO还是VO,一般都会对BO/DO中的数据进行一些转化和整合,比如将gender属性中的0转化“男”,1转化为“女”等。controller的功能主要有5点:参数校验、调用service层接口实现业务逻辑、转换业务/数据对象、组装返回对象、异常处理。
(4)、View层
又叫显示层,主要是负责前台jsp页面的表示
二、HelloSpringMVC
使用注解开发SpringMVC程序
导入依赖
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.9.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.servlet.jsp/jsp-api -->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.2.1-b03</version>
<scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.9</version>
</dependency>
编写Web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<display-name>Archetype Created Web Application</display-name>
<!--配置DispachServlet-->
<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>/hellomvc</url-pattern>
</servlet-mapping>
</web-app>
编写springmvc-servlet.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util https://www.springframework.org/schema/util/spring-util.xsd">
<!-- 添加处理映射器 -->
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
<!-- 添加处理器适配器 -->
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
<!--视图解析器:DispatcherServlet给他的ModeLAndView-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="InternalResourceViewResolver"/>
<!--前缀-->
<!--前缀-->
<property name="prefix" value="/WEB-INF/jsp/"/>
<!--后缀-->
<property name="suffix" value=".jsp"/>
<!-- handler -->
<bean name="/hello" class="com.biibili.spring.HelloController" />
</beans>
编写HelloController
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
//注意: 这里我们先导入Controller接口
public class HelloController implements Controller {
@Override
public ModelAndView handleRequest (HttpServletRequest request, HttpServletResponse response) throws Exception {
//ModeLAndView模型和视图
ModelAndView mv = new Mode1AndView();
//封装对象,放在ModeLAndView中
mv.addobject("msg","HelloSpringMVC!");
//封装要跳转的视图,放在ModelAndView中
mv.setViewName("hello"); //: /WEB-INF/jsp/hello.jsp
return mv;
}
}
编写hello.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>springmvc</title>
</head>
<body>
$END$
</body>
</html>
三、RestFul
1、概念
一种软件架构风格、设计风格,而不是标准,只是提供了一组设计原则和约束条件。它主要用于客户端和服务器交互类的软件。基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。
2、URL定义
资源:互联网所有的事物都可以被抽象为资源 资源操作:使用POST、DELETE、PUT、GET,使用不同方法对资源进行操作。 分别对应 添加、 删除、修改、查询。
3、传统方式操作资源
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
4、使用RestFul操作资源
【GET】 /users # 查询用户信息列表
【GET】 /users/1001 # 查看某个用户信息
【POST】 /users # 新建用户信息
【PUT】 /users/1001 # 更新用户信息(全部字段)
【PATCH】 /users/1001 # 更新用户信息(部分字段)
【DELETE】 /users/1001 # 删除用户信息
四、重定向和转发
1、重定向
客户发送一个请求到服务器,服务器匹配servlet,这都和请求转发一样,servlet处理完之后调用了sendRedirect()这个方法,这个方法是response的方法,所以,当这个servlet处理完之后,看到response.senRedirect()方法,立即向客户端返回这个响应,响应行告诉客户端你必须要再发送一个请求,去访问test.jsp,紧接着客户端受到这个请求后,立刻发出一个新的请求,去请求test.jsp,这里两个请求互不干扰,相互独立,在前面request里面setAttribute()的任何东西,在后面的request里面都获得不了。可见,在sendRedirect()里面是两个请求,两个响应。
redirect重定向的三种方式:
(1)、response.sendRedirect重定向跳转
@RequestMapping(value="/testredirect",method = { RequestMethod.POST, RequestMethod.GET })
public ModelAndView testredirect(HttpServletResponse response){
response.sendRedirect("/index"); return null; }
(2)、ViewResolver直接跳转
不带参数
@RequestMapping(value="/testredirect",method = { RequestMethod.POST, RequestMethod.GET })
public String testredirect(HttpServletResponse response){
return "redirect:/index";
}
带参数
@RequestMapping("/testredirect")
public String testredirect(Model model, RedirectAttributes attr) {
attr.addAttribute("test", "51gjie");//跳转地址带上test参数
attr.addFlashAttribute("u2", "51gjie");//跳转地址不带上u2参数
return "redirect:/user/users";
}
使用RedirectAttributes的addAttribute方法传递参数会跟随在URL后面,如上代码即为http:/index.action?test=51gjie
使用addFlashAttribute不会跟随在URL后面,会把该参数值暂时保存于session,待重定向url获取该参数后从session中移除,这里的redirect必须是方法映射路径,jsp无效。你会发现redirect后的jsp页面中b只会出现一次,刷新后b再也不会出现了,这验证了上面说的,b被访问后就会从session中移除。对于重复提交可以使用此来完成.
spring mvc设置下RequestMappingHandlerAdapter 的ignoreDefaultModelOnRedirect=true,这样可以提高效率,避免不必要的检索。
(3)、ModelAndView重定向
不带参数
@RequestMapping(value="/restredirect",method = { RequestMethod.POST, RequestMethod.GET })
public ModelAndView restredirect(String userName){
ModelAndView model = new ModelAndView("redirect:/main/index");
return model;
}
带参数
@RequestMapping(value="/toredirect",method = { RequestMethod.POST, RequestMethod.GET })
public ModelAndView toredirect(String userName){
ModelAndView model = new ModelAndView("/main/index");
model.addObject("userName", userName); //把userName参数带入到controller的RedirectAttributes
return model;
}
2、转发
(1)、ModelAndView
设置ModelAndView对象 , 根据view的名称 , 和视图解析器跳到指定的页面 .
页面 : {视图解析器前缀} + viewName +{视图解析器后缀}
<!-- 视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
id="internalResourceViewResolver">
<!-- 前缀 -->
<property name="prefix" value="/WEB-INF/jsp/" />
<!-- 后缀 -->
<property name="suffix" value=".jsp" />
</bean>
对应的controller类
public class ControllerTest1 implements Controller {
public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
//返回一个模型视图对象
ModelAndView mv = new ModelAndView();
mv.addObject("msg","ControllerTest1");
mv.setViewName("test");
return mv;
}
}
(2)、ServletAPI
通过设置ServletAPI , 不需要视图解析器 .
1、通过HttpServletResponse进行输出
2、通过HttpServletResponse实现重定向
3、通过HttpServletResponse实现转发
@Controller
public class ResultGo {
@RequestMapping("/result/t1")
public void test1(HttpServletRequest req, HttpServletResponse rsp) throws IOException {
rsp.getWriter().println("Hello,Spring BY servlet API");
}
@RequestMapping("/result/t2")
public void test2(HttpServletRequest req, HttpServletResponse rsp) throws IOException {
rsp.sendRedirect("/index.jsp");
}
@RequestMapping("/result/t3")
public void test3(HttpServletRequest req, HttpServletResponse rsp) throws Exception {
//转发
req.setAttribute("msg","/result/t3");
req.getRequestDispatcher("/WEB-INF/jsp/test.jsp").forward(req,rsp);
}
}
(3)、SpringMVC
通过SpringMVC来实现转发和重定向 - 无需视图解析器;
测试前,需要将视图解析器注释掉
@Controller
public class ResultSpringMVC {
@RequestMapping("/rsm/t1")
public String test1(){
//转发
return "/index.jsp";
}
@RequestMapping("/rsm/t2")
public String test2(){
//转发二
return "forward:/index.jsp";
}
@RequestMapping("/rsm/t3")
public String test3(){
//重定向
return "redirect:/index.jsp";
}
}
通过SpringMVC来实现转发和重定向 - 有视图解析器;
重定向 , 不需要视图解析器 , 本质就是重新请求一个新地方嘛 , 所以注意路径问题.
可以重定向到另外一个请求实现
@Controller
public class ResultSpringMVC2 {
@RequestMapping("/rsm2/t1")
public String test1(){
//转发
return "test";
}
@RequestMapping("/rsm2/t2")
public String test2(){
//重定向
return "redirect:/index.jsp";
//return "redirect:hello.do"; //hello.do为另一个请求/
}
}
五、数据处理
1、处理提交数据
(1)、提交的域名称和Controller处理方法的参数名一致
提交数据 : http://localhost:8080/SpringMVC/test/t?name=张三
处理方法 :
@Controller
@RequestMapping("test")
public class RedirectController {
@RequestMapping("t")
public String Test3(String name){
return "/test";
}
}
(2)、提交的域名称和Controller处理方法的参数名不一致
通过@RequestParam映射,提交数据 : http://localhost:8080/SpringMVC/test/t?username=张三
处理方法 :
@Controller
@RequestMapping("test")
public class RedirectController {
@RequestMapping("t")
public String Test3(@RequestParam("username")String name){
return "/test";
}
}
(3)、提交的是一个对象
要求提交的表单域和对象的属性名一致 , 参数使用对象即可
1、实体类
public class User {
private int id;
private String name;
private int age;
//构造
//get/set
//tostring()
}
2、提交数据 : http://localhost:8080/SpringMVC/test/t?name=张三&sex=男&age=18
3、处理方法 :
@RequestMapping("test")
public String user(User user){
System.out.println(user);
return "/test";
}
2、数据显示到前端
ModelAndView 可以在储存数据的同时,可以进行设置返回的逻辑视图,进行控制展示层的跳转;
ModelMap 继承了 LinkedMap ,除了实现了自身的一些方法,同样的继承 LinkedMap 的方法和特性;
Model 只有寥寥几个方法只适合用于储存数据,简化了新手对于Model对象的操作和理解;
(1)、通过ModelAndView
@RequestMapping("/hello")
public String hello(@RequestParam("username") String name, ModelMap model){
//封装要显示到视图中的数据
//相当于req.setAttribute("name",name);
model.addAttribute("name",name);
System.out.println(name);
return "hello";
}
(2)、ModelMap
@RequestMapping("/hello")
public String hello(@RequestParam("username") String name, ModelMap model){
//封装要显示到视图中的数据
//相当于req.setAttribute("name",name);
model.addAttribute("name",name);
System.out.println(name);
return "hello";
}
(3)、Model
@RequestMapping("/ct2/hello")
public String hello(@RequestParam("username") String name, Model model){
//封装要显示到视图中的数据
//相当于req.setAttribute("name",name);
model.addAttribute("msg",name);
System.out.println(name);
return "test";
}