一、SpringMVC 定义
SpringMVC也叫Spring Web MVC,属于表现层的框架,SpringMVC也是Spring框架的一部分,是在Spring3.0后发布的,SpringMVC和Spring无需通过中间层进行整合。
SpringMVC是Spring Framework技术组件中的一个核心模块,基于MVC设计模式开发设计的一种技术框架,提供一种Java EE领域中应用与MVC分层的解决方案。类似于Struts框架,但比Struts更加简单易用,SpringMVC是轻量级的。SpringMVC是一个框架,一个解决MVC层面的框架。
和Spring的关系:Spring框架是一站式框架,分层次。
二、为什么要使用SpringMVC
很多应用程序的问题在于处理业务数据和显示业务数据的视图对象之间存在密集耦合。通常,更新业务对象的命令都是从视图本身发起的,使视图对任何业务对象更改都有高度敏感性,而且当多个视图依赖于同一个业务对象时是没有灵活性的。
SpringMVC是一种基于Java的实现了Web MVC设计模式的请求驱动类型的轻量级Web框架,即使用了MVC架构模式的思想,将web层进行职责解耦,基于请求驱动指的就是使用请求-响应模型,框架的目的就是帮助我们简化开发,SpringMVC也是要简化我们日常Web开发的。
三、SpringMVC的强大之处
-
SpringMVC实现了即用的MVC的核心概念,它为控制器和处理器程序提供了大量与此模式相关的功能。并且当向MVC添加控制反转时,它使应用程序高度解耦,提供了通过简单的配置更改即可动态更改组件的灵活性,SpringMVC为您提供了完全控制应用程序的各个方面的力量。
-
Spring的Web MVC模块是围绕DispatcherServlet而设计的,DispatcherServlet给处理程序分派请求,执行视图解析,并且处理语言环境和主题解析,此外还为上传文件提供支持。
-
DispatcherServlet通过使用处理程序映射来决定哪一个处理程序应当处理传入的请求。处理程序映射只适用于标识使用哪一个处理程序来处理特定URL模式的映射。处理程序只有一种方法ModelAnView handleRequest(request,response)的控制器接口的实现,Spring还有一些可用的高级处理程序实现,其中一个重要的高级处理程序实现是SimpleFormController,它提供了将命令对象绑定到表单、对其执行验证等功能。
四、Servlet的劣势与不足和SpringMVC的优势
- Servlet的劣势与不足:
-
Servlet配置繁杂,写一个Servlet需要在web.xml文件中配置8行,如果一个系统中Servlet很多,则会导致web.xml文件中的内容过多,不利于管理
-
一个Servlet只能处理一个请求,方法的入口只有一个,局限性太大,如果处理类似业务,请求中根据不同入参进行不同逻辑的调用,进行代码的复用不是很灵活。
-
Servlet的分层结构不够清晰,各层之间职能划分不够明确清晰,代码耦合度较高,不利于后期的维护改造。
-
Servlet获取表单中的入参,代码编写死板,不够灵活,需要编写大量的入参获取代码。
- SpringMVC的优势:
-
SpringMVC使用简单,学习成本较低,开发效率远远高于Servlet、Struts等技术。
-
SpringMVC使得MVC分层清晰,各层的职能明确直观,各层之间良好的解耦,从而使得Web应用开发灵活方便。
-
SpringMVC提供了很多个性化功能模块,简化了很多常用需求的开发,例如:参数绑定、后台校验器、国际化、不同类型视图等。
-
清晰的角色划分:前端控制器(DispatcherServlet)、请求到处理器映射(HandlerMapping)、处理器适配器(HandlerAdapter)、视图解析器(ViewResolver)、处理器或页面控制器(Controller)、验证器(Validator)、命令对象(Command请求参数绑定到的对象就叫命令对象)、表单对象(Form Object提供给表单展示和提交到的对象就叫表单对象)。
-
由于命令对象就是一个POJO,无需继承框架特定API,可以使用命令对象直接作为业务对象。
-
和Spring其他框架无缝集成,是其他Web框架所不具备的。
-
可适配,通过HandlerAdapter可支持任何的类作为处理器。
-
可定制性,HandlerMapping、ViewResolver等能够非常简单的定制。
-
利用Spring提供的Mock对象能够非常简单的进行Web层单元测试。
-
本地化、主题的解析的支持,使我们共容易进行国际化和主题的切换。
五、SpringMVC的工作流程
-
发起请求到前端控制器(DispatcherServlet)
-
前端控制器请求HandlerMapping查找Handler
-
处理器映射器HandlerMapping向前端控制器返回Handler
-
前端控制器调用处理器适配器去执行Handler
-
处理器适配器去执行Handler
-
Handler执行完成给适配器返回ModelAndView
-
处理器适配器向前端控制器返回ModelAndView(SpringMVC框架的一个底层对象,包括Model和View)
-
前端控制器请求视图解析器去进行视图解析,根据逻辑视图名解析成真正的视图(jsp)
-
视图解析器向前端控制器返回view
-
前端控制器进行视图渲染:视图渲染将模型数据(在ModelAndView对象中)填充到request域
-
前端控制器向用户响应结果
注:Model中的数据存储在request作用域中,SpringMVC默认采用转发的方式跳到视图,本次请求结束,模型中的数据被销毁。
六、映射地址和返回值
-
@RequestMapping:用来处理请求地址映射的注解,可用于类或方法上,用于类上,表示类中所有响应请求的方法都是以该地址作为父路径。
-
controller的返回值
-
返回ModelAndView:controller方法中定义ModelAndView对象,并返回,对象中存放mode数据,指定view。
-
返回void:controller方法中的参数可以使用request,response
-
返回字符串:controller方法返回字符串可以指定逻辑视图名,通过视图解析器为物理视图地址。return "redirect:queryUser.action"与重定向相当。return "forward:editUser.action";与内部转发相当。注:重定向不能携带参数,内部转发可以携带参数。
七、Spring、SpringMVC常用注解:
注解名 | 常用参数 | 介绍 |
---|---|---|
@Component | String value() default "" 在组件中的名称 | 标注一个普通的Spring Bean类 |
@Service | String value() default "" 在组件中的名称 | 标注一个业务层组件类 |
@Repository | String value() default "" 在组件中的名称 | 标注一个dao持久层组件类 |
@Controller | String value() default "" 在组件中的名称 | 标注一个控制器组件类,声明该类为SpringMVC中的Controller |
@ResponseBody | 无 | 该注解用于将Controller的方法返回的对象,通过适当的HttpMessageConverter转换为指定格式后,写入到Response对象的body数据区。而不是解析为跳转路径。 |
@RestController | String value() default "" 在组件中的名称 | 在Spring中@RestController的作用等于@Controller + @ResponseBody |
@RequestBody | boolean required() default true; | 主要用来接收前段传递给后端的json字符串中的数据的(请求体中的数据的),**注:使用该注解时,前端不能用GET方式提交数据,只能用POST方式进行提交。一个请求该注解最多只能有一个** |
@RequestParam | value=”参数名” required=”true/false”是否包含该参数 defaultValue=""默认参数值,如果设置了该值,required=true将失效,自动为false,如果没有传该参数,就使用默认值 |
主要用于在SpringMVC后台控制层获取参数,类似是request.getParameter("name"),一个请求该注解可以有多个 |
@RequestMapping | path-指定请求路径的URL value-和path一样 method-指定该方法的请求方式 params-指定限制请求参数的条件 headers-发送的请求中必须包含的请求头 consumes-指定处理请求的提交内容类型 produces-指定返回的内容类型 |
建立请求URL和处理方法之间的对应关系 |
@PostMapping | 和@RequestMappin类似 | 细化了@RequestMapping注解,用于处理请求方法的POST类型 |
@GetMapping | 和@RequestMappin类似 | 细化了@RequestMapping注解,用于处理请求方法的GET类型 |
@Resource | name-bean的名字 type-bean的类型 |
写在字段上,可以把bean里面引用对象的setter/getter方法省略,他会自动帮你set/get,如果加上该注解会将容器中的对象注入到此,不用使用set来创建对象了**注:@Resource默认按照byName自动注入** |
@Autowired | 跟@Resource一样 | 和@Resource功能一样,**注:@Autowired默认按照byType自动注入** |
@ModelAttribute | 不指定属性名称,方法返回一个对象,指定属性名称,方法返回一个字符串 | 该Controller的所有方法在调用前,先执行@ModelAttribute方法 |
@SessionAttributes | 指定类型和名称 | 将值放到Session作用域中,**只能作用在类上** |
@PathVariable |
八、入门程序
1. 下载SpringMVC和项目相关的jar包,或在maven中导入所需要的依赖:
<!-- SpringMVC依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/aopalliance/aopalliance -->
<dependency>
<groupId>aopalliance</groupId>
<artifactId>aopalliance</artifactId>
<version>1.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.0</version>
</dependency>
<!-- Spring JDBC-->
<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring-version}</version>
</dependency>
<!-- MyBatis Spring-->
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.0</version>
</dependency>
<!-- mybatis-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.0</version>
</dependency>
<!-- mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.49</version>
</dependency>
2. 引入Spring容器基本启动配置application.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" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
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/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 扫描注解,排除mvc-servlet.xml的扫描路径,使其不冲突-->
<context:annotation-config/>
<context:component-scan base-package="com.ychs">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<!-- MyBatis配置-->
<context:property-placeholder location="classpath:jdbc.properties" system-properties-mode="NEVER"/>
<!-- 数据源-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</bean>
<!-- SqlSessionFactory-->
<bean id="factory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="typeAliasesPackage" value="com.ychs.entity"/>
</bean>
<!-- mapper-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.ychs.dao"/>
<property name="sqlSessionFactoryBeanName" value="factory"/>
</bean>
<!-- MyBatis配置结束-->
<!-- 事务配置-->
<bean id="tm" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 声明式事务-->
<tx:advice id="tx" transaction-manager="tm">
<tx:attributes>
<tx:method name="add" rollback-for="Exception"/>
<tx:method name="modify" rollback-for="Exception"/>
<tx:method name="remove" rollback-for="Exception"/>
</tx:attributes>
</tx:advice>
<!--事务管理切面配置-->
<aop:config>
<aop:pointcut id="pc" expression="execution(* com.ychs.service.*.*(..))"/>
<aop:advisor advice-ref="tx" pointcut-ref="pc"/>
</aop:config>
<!-- 事务配置结束-->
</beans>
3. 引入SpringMVC容器启动的基本配置mvc-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:mvc="http://www.springframework.org/schema/mvc"
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/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<!-- 打开注解开关-->
<mvc:annotation-driven/>
<!-- 指定扫描路径-->
<context:component-scan base-package="com.ychs.controller"/>
<!-- 配置静态资源路径-->
<mvc:resources mapping="/resources/**" location="/resources/"/>
<!-- 解决Controller方法返回的jsp名称的视图解决方案-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 指定jsp的路径-->
<property name="prefix" value="/WEB-INF/page/"/>
<!-- 视图的后缀-->
<property name="suffix" value=".jsp"/>
</bean>
</beans>
4. 在web.xml中进行相关配置整合Spring与SpringMVC容器配置
<?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">
<!-- Spring的监听-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- 引入Spring容器基本配置文件:application.xml-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:application.xml</param-value>
</context-param>
<!-- 配置编码过滤器-->
<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>
<servlet>
<servlet-name>mvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 引入SpringMVC基本配置,如果不写默认是查找mvc-servlet.xml问阿金-->
<!--<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>WEB-INF/mvc-servlet.xml</param-value>
</init-param>-->
</servlet>
<servlet-mapping>
<servlet-name>mvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
5. 以注解的方式编写相关业务代码
注:Service类要用@Service注解将其加入到Spring容器中
/**
* copyright(c)2021 zbh.ALL rights Reserved
* <p>
* 描述:院系业务实现类
*
* @author zbh
* @version 1.0
* @date 2021/5/21
*/
@Service
public class CollegeService implements IBaseService<College> {
@Autowired
private CollegeMapper mapper;
/**
* 增加记录
*
* @param college 新记录对象
* @return 成功与否
*/
@Override
public boolean add(College college) {
int result = mapper.insert(college);
return result == Constants.UPDATE_SUCCESS;
}
/**
* 修改记录
*
* @param college 修改记录对象
* @return 成功与否
*/
@Override
public boolean modify(College college) {
int result = mapper.update(college);
return result == Constants.UPDATE_SUCCESS;
}
/**
* 删除记录
*
* @param id 待删除的主键
* @return 成功与否
*/
@Override
public boolean remove(int id) {
int result = mapper.delete(id);
return result == Constants.UPDATE_SUCCESS;
}
/**
* 查询单个记录
*
* @param id 主键
* @return 查询结果
*/
@Override
public College searchById(int id) {
College college = mapper.selectById(id);
return college;
}
/**
* 查询多条记录
*
* @param conditions 查询条件
* @return 查询结果
*/
@Override
public List<College> search(Map<String, Object> conditions) {
List<College> colleges = mapper.select(conditions);
return colleges;
}
/**
* 查询总条数
*
* @param conditions
* @return
*/
@Override
public int searchTotalNumber(Map<String, Object> conditions) {
int number = mapper.searchTotalNumber(conditions);
return number;
}
}
6. 编写Handler(Controller)
注:Controller类要用@Controller注解将其加入到Spring容器中**
/**
* copyright(c)2021 zbh.ALL rights Reserved
* <p>
* 描述:
*
* @author zbh
* @version 1.0
* @date 2021/7/27
*/
@Controller
@RequestMapping(value = "/college")
public class CollegeController extends BaseController{
@Resource(name = "collegeService")
private IBaseService<College> service;
@PostMapping("/add")
public boolean add(College college) {
boolean result = service.add(college);
return result;
}
@GetMapping("/search")
@ResponseBody
public String search(String name, int limit, int page) throws IOException {
logger.debug("enter college search");
Map<String, Object> conditions = new HashMap(2);
conditions.put("name", name);
conditions.put("limit",limit);
conditions.put("page",page);
int count = service.searchTotalNumber(conditions);
List<College> colleges = service.search(conditions);
return getJson(count, colleges);
}
@GetMapping("/modifyPage")
public String modifyPage(int id, Map map) {
logger.debug("enter college modifyPage");
logger.debug("id=" + id);
College college = service.searchById(id);
logger.debug("college=" + college);
if (college != null) {
// 通过map把college带到修改页面,类似于request.setAttribute
map.put("college", college);
return "college/editCollege";
} else {
return "error";
}
}
@PostMapping("/modify")
@ResponseBody
public String modify(College college) {
logger.debug("enter college modify");
boolean result = service.modify(college);
return result + "";
}
@PostMapping("/remove")
@ResponseBody
public boolean remove(int id) {
boolean result = service.remove(id);
logger.debug("result="+result);
return result;
}
}