SpringMVC学习(具体实现+底层原理)
Posted 滑稽404#
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SpringMVC学习(具体实现+底层原理)相关的知识,希望对你有一定的参考价值。
文章目录
引人:MVC架构:
- M:model(数据层)
- V:view(视图层)
- C:Controller 数据层和视图层通过控制层(接口)互相调用
一、依赖
spring-web和spring-webmvc里的web有点不一样,所以mvc必须导spring-webmvc
通过properties控制版本,方便改版本
<properties>
<spring-version>5.3.6</spring-version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring-version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-expression -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>${spring-version}</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jsp-api</artifactId>
<version>2.0</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring-version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring-version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring-version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-beans -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring-version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring-version}</version>
</dependency>
<!--切面-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.13</version>
</dependency>
</dependencies>
二、具体配置(原理实现)
1、具体实现流程
- 所有请求经过DispatcherServlet,交给他去调度
- 通过处理器映射器通过请求与Controller组件的映射关系(Bean或者Controller组件注解)定位到具体Controller
- 返回到前端控制器,然后前端控制器通过处理器适配器找到Controller
- Controller去调用业务层返回ModelAndView
- ModelAndView通过前端控制器交给视图解析器解析
- 通过解析返回相应的视图
2、web.xml配置前端控制器
<!--配置前端控制器-->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--绑定mvc配置文件-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-mvc.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>
3、配置mvc
<!--处理器映射器-->
<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"/>
</bean>
<!--注册controller-->
<bean id="/hello" class="com.chime.controller.HelloController"/>
4、Controller
public class HelloController implements Controller{
@Override
public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
ModelAndView mv=new ModelAndView();
//业务代码
String result="Hello MVC";
mv.addObject("msg",result);
mv.setViewName("hello");
return mv;
}
}
5、404异常
- Artifacts没有lib库,需要手动添加
- 视图解析器前缀后缀错误
三、mvc注解实现
1、web.xml配置前端控制器
<!--注册前端控制器-->
<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:spring-mvc.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>
2、配置mvc
开启注解扫描需要添加context命名空间
注册mvc需要添加mvc命名空间
<!--开启注解扫描-->
<context:component-scan base-package="com.chime"/>
<!--通过前缀注册mvc注解,自动生成HandlerMapping和HandlerAdapter-->
<mvc:annotation-driven/>
<!--过滤静态资源-->
<mvc:default-servlet-handler/>
<!--注册视图解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
annotation-driven用于注册注解驱动。
一般根据前缀来注册相关的注解类
<tx:annotation-driven/>:支持事务注解的(@Transactional)
<mvc:annotation-driven/>:支持MVC注解
3、Controller
@Controller
public class HelloController {
//映射地址
@RequestMapping("/hello")
public String hello(Model model){
// 封装数据
model.addAttribute("msg","Hello");
return "hello";//交给视图解析器解析
}
}
4、使用bean注册Controller的缺点
实现Controller的类只有一个实现方法,需要一个个配(一个Bean对应一个类)
而使用Controller注解,可以写多个方法,加上Mapping来映射
四、Restful风格
1、Restful和传统传参的区别
localhost:8080/login?username=qwe&password=123
localhost:8080/login/qwe/123
localhost:8080/add?a=3&b=4
localhost:8080/add/3/4
url的Restful风格传参,需要使用@PathVariable注解声明路径变量
@RequestMapping("/add/{a}/{b}")
public String test1(@PathVariable int a,@PathVariable String b, Model model){
String result=a+b;
model.addAttribute("msg","test1"+result);
return "hello";
}
2、Restful风格的优点
- 参数名称不会直接暴露在地址栏中
- 简洁高效
3、相同url怎么控制冲突
相同的url可以通过更改请求类型来访问,get请求只能访问Get,post请求只能访问post
- 使用RequestMapping的method参数设置请求类型
- 直接使用相应类型的Mapping
@RequestMapping(value= "/add/{a}/{b}",method = RequestMethod.GET)
@GetMapping("/add/{a}/{b}")
//@RequestMapping(value= "/add/{a}/{b}",method = RequestMethod.GET)
@GetMapping("/add/{a}/{b}")
public String test1(@PathVariable int a,@PathVariable String b, Model model){
String result=a+b;
model.addAttribute("msg","test1"+result);
return "hello";
}
//@RequestMapping(value= "/add/{a}/{b}",method = RequestMethod.POST)
@PostMapping("/add/{a}/{b}")
public String test2(@PathVariable int a,@PathVariable String b, Model model){
String result=a+b;
model.addAttribute("msg","test2 "+result);
return "hello";
}
五、转发和重定向
1、有视图解析器
- 视图解析器默认转发
- 转发写出forword后,就不会拼接了,需要直接写完整
- 重定向需要写出完整地址,而且WEB-INF访问不到,不能重定向进去
WEB-INF是WEB应用的安全目录,只允许服务端访问,不允许客户端访问(只能转发,不能重定向)
重定向就是服务端确定url后,将url交给客户端,客户端再直接访问,所有不能重定向到WEB-INF
- 携带数据用转发,重定向如果需要携带数据需要特殊jar包
@RequestMapping("/test3")
public String test3(Model model){
model.addAttribute("msg","转发");
//return "forward:hello.jsp";
return "hello";
}
@RequestMapping("/test4")
public String test4(Model model){
model.addAttribute("msg","重定向");
return "redirect:/test.jsp";
}
2、不用视图解析器
- 转发和重定向都要写出地址
- 转发可以访问WEB-INF
@RequestMapping("/test3")
public String test3(Model model){
model.addAttribute("msg","转发");
return "forward:/WEB-INF/jsp/hello.jsp";
}
@RequestMapping("/test4")
public String test4(Model model){
model.addAttribute("msg","重定向");
return "redirect:/index.jsp";
}
六、Controller方法参数
1、普通类型参数
可以使用@RequestParam设置参数别名
localhost:8080/test5?username=qwe
qwe就被name接收了
@RequestMapping("/test5")
public String test5(@RequestParam("username") String name,Model model){
model.addAttribute("username",name);
return "hello";
}
2、对象参数
前端根据参数名自动匹配对象的属性
http://localhost:8080/anno/test6?id=5&sex=男
没有name字段,则person对象的name属性为空
@RequestMapping("/test6")
public String test6(Person person, Model model){
System.out.println(person);
return "hello";
}
七、前台乱码
web.xml里注册格式过滤器
<!--字符格式过滤器-->
<filter>
<filter-name>encoding</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
八、Json
1、前端
<script>
var user={
id : "101",
name: "张三",
sex : "男"
};
console.log("对象:"+user);//会输出Object,不能显示属性
console.log(user);
var json = JSON.stringify(user);
console.log("Json:"+json);
var obj = JSON.parse(json);
console.log("Obj:"+obj);
console.log(obj);
</script>
- Json是个有多个键值对的字符串
- 输出对象不能拼接字符串,如果拼接字符串会显示Object
2、后端
-
@RestController:在Controller上声明,类中所有方法不会返回页面,只会返回值
-
@ResponseBody:在Controller方法上上面,该方法不会返回页面,只会返回值
一般使用obj.toString()或者json转换包来返回json数据
@RequestMapping("json1")
// @ResponseBody
public String json1(以上是关于SpringMVC学习(具体实现+底层原理)的主要内容,如果未能解决你的问题,请参考以下文章
学习笔记——SpringMVC处理响应数据;SpringMVC处理请求域响应乱码问题