SpringMVC框架学习笔记(一)
Spring Web MVC Framework
基于WEB项目都需要发布到WEB服务器当中,WEB服务器分为开源和商业,针对开源比较流行的
Tomcat
和Jetty
,使用Tomcat开发的时候有一些慢,我们可以考虑使用Maven插件的方式进行开发测试Jetty
或者Tomcat
一、Maven构建WEB项目
使用Jetty作为WEB服务的配置。
(1)构建WEB项目,使用Maven的骨架构建目录
- 构建WEB项目默认的
web.xml
版本比较低,不支持EL表达式,使用需要自己构建
<?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">
</web-app>
- Maven项目默认不跟WEB服务器关联,需要单独引入ServletAPI的支持
<dependencies>
<!-- 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>
<!-- https://mvnrepository.com/artifact/javax.servlet.jsp/javax.servlet.jsp-api -->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.3.3</version>
<scope>provided</scope><!--测试和编译期间起作用-->
</dependency>
</dependencies>
(2)安装Jetty服务Maven插件
<!-- https://mvnrepository.com/artifact/org.mortbay.jetty/jetty-maven-plugin -->
<dependency>
<groupId>org.mortbay.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>8.1.16.v20140903</version>
<scope>test</scope>
</dependency>
(3)配置插件
只需要将GAV进行复制到插件即可,因为是第三方的插件,我们会修改settings.xml文件
<plugins>
<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>8.1.16.v20140903</version>
<configuration>
<scanIntervalSeconds>10</scanIntervalSeconds><!--每隔10秒自动扫描一次class文件,如果被修改==>自动重启-->
<webApp>
<contextPath>/mvc</contextPath>
</webApp><!--发布路径-->
<stopKey/>
<stopPort/>
</configuration>
</plugin>
</plugins>
- settings.xml中添加第三方的运行
<pluginGroups>
<!-- pluginGroup
| Specifies a further group identifier to use for plugin lookup.
<pluginGroup>com.your.plugins</pluginGroup>
-->
<pluginGroup>org.mortbay.jetty</pluginGroup>
<pluginGroup>org.eclipse.jetty</pluginGroup>
</pluginGroups>
(4)插件运行测试
运行后访问http://127.0.0.1:8080/mvc/
发现显示500错误:
解决方法
二、Spring Web MVC 环境搭建
MyBatis的ORM框架(对象关系映射==>英语:Object Relational Mapping)
是针对于持久化层数据库的JDBC操作的封装,Spring Web MVC是针对Java Web的封装(HttpServet),可以支持数据的转换(默认:获取都是字符串和字符串数组)、文件上传、验证等功能。
Spring Web MVC框架是Spring框架的一个模块而已
(1)Spring Web MVC的框架安装
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.9</version>
</dependency>
引入成功
(2)注册前端控制器DispatcherServlet
所有的请求需要经过该Servlet处理,并且在服务器启动时实例化
重要作用:读取默认核心配置文件的位置和名称或者自定义核心配置文件的名称和位置
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup><!--服务器启动后就对Servlet进行实例化和初始化,并且值越小优先级越高-->
</servlet>
<!-- 设置前端控制器映射 -->
<!-- / :所有请求都需要被前端控制器处理,排除访问JSP -->
<!-- /*:所有请求都需要被前端控制器处理,包含访问JSP -->
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
源码中其继承HttpServletBean
public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware {
public static final String DEFAULT_NAMESPACE_SUFFIX = "-servlet";
}
(3)默认的核心配置文件位置和名称规则
规则
/WEB-INF/[servlet-name]-servlet.xml
=>所以应该命名为:
/WEB-INF/springmvc-servlet.xml
Spring MVC是Spring的一部分,使用的核心配置文件就是Spring的核心配置文件
<?xml version="1.0" encoding="UTF-8"?>
<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">
</beans>
(4)新建一个控制器,就是一个不同的Java类不需要继承任何东西
不推荐的版本:
package com.yue.controller;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
/*该版本永远不会使用:太麻烦,不灵活*/
public class IndexController implements Controller {
//handleRequest理解为Servlet中的service方法(doGet/doPost)
@Override
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
//识别HTML和JavaScript标签
out.write("<h3>"+Math.random()+"</h3>");
out.close();
return null;//响应一个空白的页面
}
}
(5)注册控制器建立映射关系
不推荐的版本:
<?xml version="1.0" encoding="UTF-8"?>
<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="com.yue.controller.IndexController" id="/index"/>
<bean class="com.yue.controller.IndexController" id="/index.asp"/>
<bean class="com.yue.controller.IndexController" id="/index.php"/>
</beans>
运行成功
(6)使用注解方式,极力推荐方式,灵活方面
package com.yue.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import java.util.Random;
//标注其是一个控制器并且对其进行实例化操作,名称为类名首字母小写roleController
/*
可以理解为:
<servlet>
<servlet-name>roleController</servlet-name>
<servlet-class>com.yue.controller.RoleController</servlet-class>
</servlet>
*/
@Controller//也可以理解为@WebServlet
@RequestMapping("/role")//提取公共部分,此类中访问路径就需要再加上"/role"
public class RoleController {
/*
<servlet-mapping>
<servlet-name>roleController</servlet-name>
<url-pattern>/add</url-pattern>
<url-pattern>/insert</url-pattern>
</servlet-mapping>
*/
@RequestMapping(value={"/add","/insert"})//@RequestMapping(value={"/role/add","/role/insert"})
public ModelAndView add(){
System.out.println(new Random().nextInt());
return null;
}
@RequestMapping("/update")
public ModelAndView update(){
System.out.println(Math.random());
return null;
}
}
在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:context="http://www.springframework.org/schema/context"
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">
<bean class="com.yue.controller.IndexController" id="/index"/>
<bean class="com.yue.controller.IndexController" id="/index.asp"/>
<bean class="com.yue.controller.IndexController" id="/index.php"/>
<!-- 扫描注解 -->
<!-- By default, the Spring-provided @Component, @Repository, @Service,
@Controller, @RestController, @ControllerAdvice, and @Configuration stereotypes
will be detected. -->
<context:component-scan base-package="com.yue.controller"/>
</beans>
注意:
映射的路径需要保持唯一性,@RequestMapping
可以标注在方法上或者类
源码说明:
@Target({ElementType.TYPE, ElementType.METHOD})//使用范围:方法或者类
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
public @interface RequestMapping {
三. SpringMVC 工作原理
- 客户端发起请求(http)通过web.xml找到 DispatchServlet(前端控制器);
- 由DispatchServlet控制器通过配置文件(servletName-servlet.xml)寻找到一个或多个HandlerMapping(映射处理器),找到用于处理请求的controller(后端控制器);
- DispatchServlet将请求提交到controller;
- Controller处理业务逻辑后,返回数据 ModelAndVIew给DispatchServlet;
- DispatchServlet寻找到一个或多个ViewResolver(视图解析器),找到ModelAndVIew指定的视图;
- DispatchServle负责将结果返给View(客户端JSP页面),封装Http;
- view响应页面的HTTP请求,返回响应数据,浏览器绘制页面。
四、服务端控制器之间跳转
在WEB的时候;
JSP/Servlet
关系:JSP(动态生成HTML页面)就是Servlet(控制器),Servlet就是JSP.服务端之间的跳转涉及:请求转发
和重定向
请求转发
:可以通过HttpServletRequest
传递一次请求转发的数据(使用频繁),不该请求的路径重定向
:url?name=tomcat&hobby=basketball&hobby=football
,改变路径
(1)Controller跳转JSP页面,可以访问到WEB-INF
文件,这是请求转发
多包的扫描方式,使用逗号分隔
<context:component-scan base-package="com.yue.**.controller,org.os.web"/>
package org.os.web;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
@Controller
@RequestMapping("/users")
public class UserController {
@RequestMapping(value = "/add")
public ModelAndView jsp01(){
ModelAndView mav = new ModelAndView("/WEB-INF/jsp/result01.jsp");
return mav;
}
@RequestMapping(path = "/insert")
public ModelAndView jsp02(){
ModelAndView mav = new ModelAndView();
mav.setViewName("/WEB-INF/jsp/result02.jsp");
return mav;
}
}
viewName
属性赋值的时候,字符串没有设置任何的前置的情况下,默认使用请求转发到JSP页面
(2)Controller跳转JSP页面:重定向,需要给viewName设置前缀标识redirect:
ackage org.os.web;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.view.UrlBasedViewResolver;
@Controller
@RequestMapping("/user")
public class UserController {
@RequestMapping(value="/update")
public ModelAndView jsp03(){
ModelAndView mav = new ModelAndView("redirect:/view/test01.jsp");
return mav;
}
@RequestMapping(path="/edit")
public ModelAndView jsp04(){
ModelAndView mav = new ModelAndView();
mav.setViewName(UrlBasedViewResolver.REDIRECT_URL_PREFIX+"/view/test02.jsp");
return mav;
}
}
(3)Controller跳转Controller:重定向,需要给viewName设置前缀标识redirect:
@RequestMapping(path="/delete")
public ModelAndView controller01(){
ModelAndView mav = new ModelAndView();
mav.setViewName(UrlBasedViewResolver.REDIRECT_URL_PREFIX+"/user/add");
return mav;
}
(4)Controller跳转Controller:请求转发,不需要设置标识,除非启用JSP视图解析器
@RequestMapping(path="/remove")
public ModelAndView controller02(){
ModelAndView mav = new ModelAndView();
mav.setViewName("/user/insert");
return mav;
}
针对于JSP的请求转发,Spring MVC提供了专门拼接的视图解析器,当你设置解析器之后,只要是跳转的字符串没有设置任何的前缀都是请求转发到JSP页面
<!-- 请求转发JSP的视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="jspViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
只对请求转发起作用,重定向无用
省略公共部分的拼接
请求转发跳转控制器必须设置前缀
@RequestMapping(value="/add")
public ModelAndView jsp01(){
ModelAndView mav = new ModelAndView("result01");
return mav;
}
@RequestMapping(path="/insert")
public ModelAndView jsp02(){
ModelAndView mav = new ModelAndView();
mav.setViewName("result02");
return mav;
}
@RequestMapping(path="/remove")
public ModelAndView controller02(){
ModelAndView mav = new ModelAndView();
//设置请求转发到Controller必须设置forward前缀
mav.setViewName("forward:/user/insert");
return mav;
}
附录:读取本地自定义核心配置文件
(1)使用前端控制器配置本地自定义核心配置文件
<!-- 注册前端控制器 -->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/springmvc.xml,classpath:springmvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup><!-- 服务器启动就对该Servlet进行实例化和初始化,并且值越小优先级越高 -->
</servlet>
<!-- 设置前端控制器映射 -->
<!-- / :所有请求都需要被前端控制器处理,排除访问JSP -->
<!-- /*:所有请求都需要被前端控制器处理,包含访问JSP -->
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
(2)使用监听器配置本地自定义核心配置文件
<?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">
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/springmvc.xml</param-value>
</context-param>
<!-- 注册前端控制器 -->
<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.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup><!-- 服务器启动就对该Servlet进行实例化和初始化,并且值越小优先级越高 -->
</servlet>
<!-- 设置前端控制器映射 -->
<!-- / :所有请求都需要被前端控制器处理,排除访问JSP -->
<!-- /*:所有请求都需要被前端控制器处理,包含访问JSP -->
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
</web-app>