Spring MVC是一个基于Java的实现了MVC设计模式的请求驱动类型的轻量级Web框架,通过把Model,View,Controller分离,将web层进行职责解耦,把复杂的web应用分成逻辑清晰的几部分,简化开发,减少出错,方便组内开发人员之间的配合。
(1)可以支持各种视图技术,而不仅仅局限于JSP;
(2)与Spring框架集成(如IoC容器、AOP等);
(3)清晰的角色分配:前端控制器(dispatcherServlet) ,请求到处理器映射(handlerMapping),处理器适配器(HandlerAdapter),视图解析器(ViewResolver)。
(4) 支持各种请求资源的映射策略。
Spring MVC 是 Spring 框架中的一个模块,专注于支持 Web 应用程序的开发。尽管 Spring 框架本身提供了很多功能,包括依赖注入、事务管理、AOP 等,但它并没有提供专门的支持 Web 开发的解决方案。这就是 Spring MVC 出现的原因。
以下是为什么在使用 Spring 框架的同时还需要使用 Spring MVC 的一些原因:
虽然 Spring 框架本身包含了一些基本的 Web 支持,但 Spring MVC 提供了更为专业、全面的解决方案,适用于需要构建 Web 应用程序或 RESTful 服务的场景。因此,当你需要开发 Web 应用时,使用 Spring MVC 是一个自然的选择。
(1)用户发送请求至前端控制器DispatcherServlet;
(2)DispatcherServlet收到请求后,调用HandlerMapping处理器映射器,请求获取Handler;
(3)处理器映射器根据请求url找到具体的处理器Handler,生成处理器对象及处理器拦截器(如果有则生成),一并返回给DispatcherServlet;
(4)DispatcherServlet 调用 HandlerAdapter处理器适配器,请求执行Handler;
(5)HandlerAdapter 经过适配调用 具体处理器进行处理业务逻辑;
(6)Handler执行完成返回ModelAndView;
(7)HandlerAdapter将Handler执行结果ModelAndView返回给DispatcherServlet;
(8)DispatcherServlet将ModelAndView传给ViewResolver视图解析器进行解析;
(9)ViewResolver解析后返回具体View;
(10)DispatcherServlet对View进行渲染视图(即将模型数据填充至视图中)
(11)DispatcherServlet响应用户。
前端控制器 DispatcherServlet:接收请求、响应结果,相当于转发器,有了DispatcherServlet 就减少了其它组件之间的耦合度。
处理器映射器 HandlerMapping:根据请求的URL来查找Handler
处理器适配器 HandlerAdapter:负责执行Handler
处理器 Handler:处理器,需要程序员开发
视图解析器 ViewResolver:进行视图的解析,根据视图逻辑名将ModelAndView解析成真正的视图(view)
视图View:View是一个接口, 它的实现类支持不同的视图类型,如jsp,freemarker,pdf等等
答:是单例模式,在多线程访问的时候有线程安全问题,解决方案是在控制器里面不能写可变状态量,如果需要使用这些可变状态,可以使用ThreadLocal机制解决,为每个线程单独生成一份变量副本,独立操作,互不影响。
1、创建一个web项目
2、导入SpringMvc对应的依赖
3、配置web.xml , 注册DispatcherServlet
这里暂停一下,我们在学习myBatis,Spring时可能就没有使用web框架,使用Junit提供的测试就可以了,但是Mvc是用于专注web开发的,我们需要用到浏览器,服务器。我们在学习JavaWeb的时候,就是在web.xml通过配置servlet映射,来将浏览器的需求传递给服务器,并且做出相应的响应的
<servlet>
<servlet-name>helloservlet-name>
<servlet-class>com.x.servlet.HelloServletservlet-class>
servlet>
<servlet-mapping>
<servlet-name>helloservlet-name>
<url-pattern>/hellourl-pattern>
servlet-mapping>
public class HelloServlet extends HttpServlet {
// 由于get或者post只是请求实现的不同的方式,可以相互调用,业务逻辑都一样
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//ServletOutputStream outputStream = resp.getOutputStream();
PrintWriter writer = resp.getWriter();//响应流
writer.print("Hello,Servlet");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doPost(req, resp);
}
}
好了,这里只是带大家回顾一下JavaWeb的知识。
<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">
<servlet>
<servlet-name>SpringMVCservlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
<init-param>
<param-name>contextConfigLocationparam-name>
<param-value>classpath:springmvc-servlet.xmlparam-value>
init-param>
<load-on-startup>1load-on-startup>
servlet>
<servlet-mapping>
<servlet-name>SpringMVCservlet-name>
<url-pattern>/url-pattern>
servlet-mapping>
web-app>
我们在上面提到过,SpringMvc的核心就是DispatcherServlet
它接收所有的请求并进行转发与处理。
4、编写SpringMVC 的 配置文件!名称:springmvc-servlet.xml : [servletname]-servlet.xml 说明,这里的名称要求是按照官方来的
<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">
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
bean>
<bean id="/hello" class="com.kolt.controller.HelloController"/>
beans>
5、编写我们要操作业务Controller ,要么实现Controller接口,要么增加注解(下面讲);需要返回一个 ModelAndView,装数据,封视图;
public class HelloController implements Controller {
@Override
public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
ModelAndView modelAndView = new ModelAndView();
//业务代码
String result = "HelloSpringMVC";
modelAndView.addObject("msg",result);
//视图跳转
modelAndView.setViewName("test");
return modelAndView;
}
}
大部分步骤是不变的,spring的配置文件略有区别
<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.kolt.controller"/>
<mvc:default-servlet-handler/>
<mvc:annotation-driven/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
bean>
beans>
@Controller//代表这个类会被spring接管,所有方法,如果返回值是string。并且有具体的页面可以跳转,它就会被视图解析器解析
public class HelloController {
@RequestMapping("/h1")
public String hello(Model model){
//封装数据
model.addAttribute("msg","Hello,SpringMVC");
return "hello";//会被视图解析器处理
}
}
我们是不是没有在配置文件中声明 Bean
,因为什么呀,我们开了自动扫描,而且在类上使用了 @Controller
注解(相信大家对这种注解都不陌生。
1、Controller
这个就不讲了,大家都比较熟悉
2、@RequestMapping
@RequestMapping注解用于映射url到控制器类或一个特定的处理程序方法。可用于类或方法上。 用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。(这个没啥难的,大家都知道)
@Controller
@RequestMapping("/admin")
public class ControllerTest3 {
@RequestMapping("/t1")
public String test4(Model model){
model.addAttribute("msg","admin");
return "admin/admin";
}
}
Spring MVC 的 @RequestMapping 注解能够处理 HTTP 请求的方法, 比如 GET, PUT, POST, DELETE 以 及 PATCH。 所有的地址栏请求默认都会是 HTTP GET 类型的。 方法级别的注解变体有如下几个: 组合注解
@GetMapping
@PostMapping
@PutMapping
@DeleteMapping
@PatchMapping
@GetMapping
是一个组合注解 它所扮演的是 @RequestMapping(method =RequestMethod.GET)
的一个快捷方式。 平时使用的会比较多!
3、@ResponseBody
@ResponseBody
加了这个注解,他就不会走视图解析器,会直接返回一个字符串,而不是去找界面
@RequestMapping(value = "/t1", produces = "application/json;charset=utf-8")
@ResponseBody//加了这个注解,他就不会走视图解析器,会直接返回一个字符串,而不是去找界面
public String json1() throws JsonProcessingException {
//jackson,ObjectMapper
ObjectMapper objectMapper = new ObjectMapper();
User user = new User("hh",4,"男");
String str = objectMapper.writeValueAsString(user);
return str;
}
}
或者直接在类上使用 @RestController
,效果是一样的。
RestController
public class UserController {
@RequestMapping(value = "/t1", produces = "application/json;charset=utf-8")
public String json1() throws JsonProcessingException {
//jackson,ObjectMapper
ObjectMapper objectMapper = new ObjectMapper();
User user = new User("hh",4,"男");
String str = objectMapper.writeValueAsString(user);
return str;
}
}
概念 :Restful就是一个资源定位及资源操作的风格。不是标准也不是协议,只是一种风格。基于这个风格设 计的软件可以更简洁,更有层次,更易于实现缓存等机制。
功能 资源:互联网所有的事物都可以被抽象为资源 资源操作:使用POST、DELETE、PUT、GET,使用不同方法对资源进行操作。 分别对应 添加、 删除、修改、查询。
传统方式操作资源 :通过不同的参数来实现不同的效果!方法单一,post 和 get
http://127.0.0.1/item/queryItem.action?id=1 查询,GET
http://127.0.0.1/item/saveItem.action 新增,POST
http://127.0.0.1/item/updateItem.action 更新,POST
http://127.0.0.1/item/deleteItem.action?id=1 删除,GET或POST
使用RESTful操作资源 : 可以通过不同的请求方式来实现不同的效果!如下:请求地址一样,但是功能 可以不同!
http://127.0.0.1/item/1 查询,GET
http://127.0.0.1/item 新增,POST
http://127.0.0.1/item 更新,PUT
http://127.0.0.1/item/1 删除,DELETE
@Controller
public class RestFulController {
//原本的写法:http://localhost:8080/4/add?a=1&b=2
//RestFul:
@PostMapping("/add/{a}/{b}")
public String test1(@PathVariable int a, @PathVariable int b, Model model) {
int res = a + b;
model.addAttribute("msg","结果为"+res);
return "admin/admin";
}
@RequestMapping(value = "/add/{a}/{b}",method = RequestMethod.GET)
public String test2(@PathVariable int a, @PathVariable int b, Model model) {
int res = a + b;
model.addAttribute("msg","结果为"+res);
return "admin/admin";
}
}
public String test1(Model model){
model.addAttribute("msg","ModelTest1");
//重定向
return "redirect:/index.jsp";
//转发
return "forward:/index.jsp";
}
第一种: 通过 ModelAndView
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;
}
}
第二种: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";
}
第三种:通过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";
}
对比:
Model 只有寥寥几个方法只适合用于储存数据,简化了新手对于Model对象的操作和理解;
ModelMap 继承了 LinkedMap ,除了实现了自身的一些方法,同样的继承 LinkedMap 的方法和特 性;
ModelAndView 可以在储存数据的同时,可以进行设置返回的逻辑视图,进行控制展示层的跳转。
SpringMVC的处理器拦截器类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理。开 发者可以自己定义一些拦截器来实现特定的功能。
过滤器与拦截器的区别:拦截器是AOP思想的具体应用。
过滤器:
servlet规范中的一部分,任何java web工程都可以使用 在url-pattern中配置了/*之后,可以对所有要访问的资源进行拦截
拦截器
拦截器是SpringMVC框架自己的,只有使用了SpringMVC框架的工程才能使用 拦截器只会拦截访问的控制器方法, 如果访问的是jsp/html/css/image/js是不会进行拦截的
想要自定义拦截器,必须实现 HandlerInterceptor 接口。
public class MyInterceptor implements HandlerInterceptor {
//在请求处理的方法之前执行
//如果返回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("------------清理------------");
}
}
还要在spring的配置文件中声明
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.kolt.interceptor.MyInterceptor"/>
mvc:interceptor>
mvc:interceptors>
Annontation
是Java5开始引入的新特征,中文名称叫注解。它提供了一种安全的类似注释的机制,用来将任何的信息或元数据(metadata)与程序元素(类、方法、成员变量等)进行关联。为程序的元素(类、方法、成员变量)加上更直观更明了的说明,这些说明信息是与程序的业务逻辑无关,并且供指定的工具或框架使用。
Annontation
像一种修饰符一样,应用于包、类型、构造方法、方法、成员变量、参数及本地变量的声明语句中。 Java注解是附加在代码中的一些元信息,用于一些工具在编译、运行时进行解析和使用,起到说明、配置的功能。注解不会也不能影响代码的实际逻辑,仅仅起到辅助性的作用。包含在 java.lang.annotation
包中。
1、生成文档。这是最常见的,也是java 最早提供的注解。常用的有@param
@return
等
2、跟踪代码依赖性,实现替代配置文件功能。比如Dagger 2
依赖注入,java 开发比如我们的 Spring框架,将大量注解配置,具有很大用处;
3、在编译时进行格式检查。如@override
放在方法前,如果你这个方法并不是覆盖了超类方法,则编译时就能检查出。
注解本质是一个继承了Annotation
的特殊接口,其具体实现类是Java 运行时生成的动态代理类。而我们通过反射获取注解时,返回的是Java 运行时生成的动态代理对象$Proxy1
。通过代理对象调用自定义注解(接口)的方法,会最终调用AnnotationInvocationHandler
的invoke
方法。该方法会从memberValues
这个Map 中索引出对应的值。而memberValues
的来源是Java 常量池。
注解在实际开发中非常常见,比如 Java 原生的 @Overried、@Deprecated 等,Spring的 @Controller、@Service等,Lombok 工具类也有大量的注解,不过在原生 Java 中,还提供了元 Annotation(元注解),他主要是用来修饰注解的,比如 @Target、@Retention、@Document、@Inherited 等。
@Target
:标识注解可以修饰哪些地方,比如方法、成员变量、包等,具体取值有以下几种:ElementType.TYPE/FIELD/METHOD/PARAMETER/CONSTRUCTOR/LOCAL_VARIABLE/ANNOTATION_TYPE/PACKAGE/TYPE_PARAMETER/TYPE_USE
@Retention
:什么时候使用注解:SOURCE(编译阶段就丢弃) / CLASS(类加载时丢弃) / RUNTIME(始终不会丢弃),一般来说,我们自定义的注解都是 RUNTIME 级别的,因为大多数情况我们是根据运行时环境去做一些处理,一般需要配合反射来使用,因为反射是 Java 获取运行是的信息的重要手段
@Document
:注解是否会包含在 javadoc 中;
@Inherited
:定义该注解与子类的关系,子类是否能使用。
如何自定义注解?
创建一个自定义注解:与创建接口类似,但自定义注解需要使用 @interface
添加元注解信息,比如 @Target、@Retention、@Document、@Inherited 等
创建注解方法,但注解方法不能带有参数
注解方法返回值为基本类型、String、Enums、Annotation 或其数组
注解可以有默认值;
@Target(FIELD)
@Retention(RUNTIME)
@Documented
public @interface CarName {
String value() default "";
1、解决post请求乱码问题:在web.xml中配置一个CharacterEncodingFilter过滤器,设置成utf-8;
<filter>
<filter-name>CharacterEncodingFilterfilter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilterfilter-class>
<init-param>
<param-name>encodingparam-name>
<param-value>utf-8param-value>
init-param>
filter>
<filter-mapping>
<filter-name>CharacterEncodingFilterfilter-name>
<url-pattern>/*url-pattern>
filter-mapping>
2、get请求中文参数出现乱码解决方法有两个:
修改tomcat配置文件添加编码与工程编码一致,如下:
2.另外一种方法对参数进行重新编码:
String userName = new String(request.getParamter("userName").getBytes("ISO8859-1"),"utf-8")
ISO8859-1是tomcat默认编码,需要将tomcat编码后的内容按utf-8编码。
值得一提的是乱码的情况可能会有很多种,需要大家根据不同的情况去进行不同的处理