Spring 框架提供了构建 Web应用程序的全功能 MVC 模块。使用 Spring 可插入的 MVC 架构,从而在使用Spring进行WEB开发时,可以选择使用Spring的Spring MVC框架或集成其他MVC开发框架,如Struts1(现在一般不用),Struts 2(一般老项目使用)等。
SpringMVC的优点:
1、SpringMVC使用简单,学习成本低。学习难度小于Struts2,Struts2用不上的多余功能太多。
2、SpringMVC很容易就可以写出性能优秀的程序,Struts2要处处小心才可以写出性能优秀的程序(指MVC部分)
3、SpringMVC灵活性强。
先来看看以前的项目体系结构(Servlet):
首先用户的请求会到达 Servlet,然后根据请求调用相应的 Java Bean,并把所有的显示结果交给 JSP 去完成,这样的模式我们就称为 MVC 模式。
M 代表 模型(Model) :模型就是数据,dao、bean
V 代表 视图(View) : 就是网页, JSP,用来展示模型中的数据
C 代表 控制器(controller) 控制器的作用就是把不同的数据(Model),显示在不同的视图(View)上,Servlet 扮演的就是这样的角色。
在以后的项目中,model层(从数据库中查找数据)可以被mybatis的mapper替换掉,service层可以被Spring处理。那么以后在Controller层中调用service时,就要用ApplicationContext来创建它。如果一个Controller创建一个它,那就要创建许多个ApplicationContext容器,太浪费了(我们发现以前我们的项目中,每一个Controller只是完成了doGet、doPost方法,大型的资源浪费。接下来我们看看用Spring管理Servlet。),所以这时就要将所有的容器共用一个。
在了解完SpringMVC后,可以去看看SpringMVC与Servlet的区别,有助于理解
接下来我们创建一个SpringMVC项目
先导入依赖的jar包
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-webmvcartifactId>
<version>5.2.5.RELEASEversion>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-ormartifactId>
<version>5.2.5.RELEASEversion>
dependency>
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatis-springartifactId>
<version>2.0.4version>
dependency>
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatisartifactId>
<version>3.5.4version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>8.0.16version>
dependency>
修改web.xml文件
<web-app>
<display-name>Archetype Created Web Applicationdisplay-name>
<servlet>
<servlet-name>springmvcservlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
<init-param>
<param-name>contextConfigLocationparam-name>
<param-value>classpath:applicationContext.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>
这时就有了Spring容器了。
以前我们创建一个Servlet就要创建一个类继承HttpServlet了,这样太麻烦了。
上面DispatcherServlet已经为我们创建了Spring容器了,真正DispatcherServlet中获取到的所有请求都要交给Spring容器来检查它发给谁(转给那个真正处理业务的类,而这个类只要是Spring中的bean就行了)
下面这个类就相当于是一个大的Servlet,而里面的每个方法就是以前我们项目中的每一个Controller类
@Controller //将他放到Spring的IoC容器中了
@RequestMapping(value="/test")//请求映射地址
// http://www.jjjjj.com/test/test.do 这个请求中的test就是RequestMapping中配置的部分
public class TestController {
@RequestMapping(value="/foo.do") //设置详细的请求就比如上面请求的test.do的部分
public void foo() {//替代了之前的Servlet,之后这个类中的所有其他方法(加@RequestMapping后)都是一个Servlet接口了
System.out.println("运行到这里了");
}
}
这时只要我们前端的请求写对了,发送到了web.xml后与
匹配,匹配上了Tomcat就将这个请求给了DispatcherServlet,它里面有一个HandlerMapping,这个HandlerMapping关心的是发送来的请求和目标位置(真正要访问的内容)之间的关系。然后DispatcherServlet找到我们所有加有@Controller的bean,然后将请求与@RequestMapping
的值依次匹配,匹配到对应的方法上,然后DispatcherServlet会通过反射调用匹配到的这个方法(比如请求为: http://localhost:8080/test/foo.do,则会匹配到配置@RequestMapping
值为foo.do的方法上,即上面的foo()方法 ),这时请求就进入到了服务器。(这里描述的是SpringMVC的原理,后文会详细讲解)
这时又有一个疑问,原来的Servlet能控制是接受get请求或者post请求。SpringMVC怎么实现呢?看下面:
@Controller
@RequestMapping("/test")
public class TestController {
@RequestMapping(value = "/doo.do", method = RequestMethod.POST)
public void doo() {
System.out.println("这里是doo");
}
}
method = RequestMethod.POST
表示可以接收post请求。
这时我们通过get访问,他会返回405错误,因为我们这里设置接收的是Post请求,而不支持get请求。
如果想让同一个请求get方法和post方法执行的逻辑不一样,那么就写两个方法,让他们的@RequestMapping
的value值相同,但是method分别支持不同的请求就OK了。
但是原来的doGet,doPost方法中有两个参数 ,我们现在这个没有这两个参数,那么前端怎么传参呢?
给方法加形参就可以解决了(注意:形参名要和请求的key值相同,不过也可以通过@RequestParam来设置)
@RequestMapping(value = "/doo.do", method = {RequestMethod.GET})
public void doo(String str) {//这时前端传来的参数名必须是str
System.out.println("这里是doo:" + str);
}
比如前端发送请求:localhost:8080/user/doo.do?str=zaq
则这时控制台会输出:这里是doo:zaq。即可以获取到前端传来的参数了
@RequestMapping(value = "/doo.do", method = {RequestMethod.GET})
public void doo(@RequestParam(value = "yyy",required = true, defaultValue = "我是一个小String") String str) {
//这时如果前端传入的参数的key为yyy,则可以获取到前端传来的值,如果没传参或者参数的key值不是yyy,则默认值为:我是一个小String
System.out.println("这里是doo:" + str);
}
@RequestMapping(value = "/doo.do", method = {RequestMethod.GET})
public void doo(@RequestParam(value = "yyy",required = true) String str) {
//required属性表示是否必须传yyy这个值,如果没有设置默认值且required值为true,那么前端请求要是没传参或者传入的参数的key值不是yyy,那么就会有400错误
System.out.println("这里是doo:" + str);
}
现在再看看原来的接收前端传入的参数的过程,很麻烦
我们现在接收前端的参数就很简单了,如果接收到前端传来的一个一个字段,那我们先创建一个实体类,只要传来的参数与实体类的属性名一一对应,它就能将参数放到对象中。
@RequestMapping(value = "/test.do", method = {RequestMethod.GET})
public void test(User user) {
System.out.println("这里是test:" + user.getUsername() +","+ user.getPwd());
}
有时候HttpServletRequest和HttpServletResponse这两个参数又很有用,必须加,怎么办?
先导入jar包
<dependency>
<groupId>javax.servletgroupId>
<artifactId>javax.servlet-apiartifactId>
<version>4.0.1version>
<scope>providedscope>
dependency>
这时就可以操作HttpServletRequest、HttpServletResponse了
@RequestMapping(value = "/test2.do", method = {RequestMethod.GET})
public void test2(HttpServletRequest request, HttpServletResponse response) {
System.out.println(request.getParameter("username"));
try {
response.setContentType("text/html; charset=utf8");
response.getWriter().println("使用resp返回内容");
} catch (IOException e) {
e.printStackTrace();
}
}
session怎么用呢?
@RequestMapping(value = "/test3.do", method = {RequestMethod.GET})
public void test3(User user, HttpSession session) {
System.out.println(session.getId());
}
接下来用SpringMVC实现一个简单的登录过程
@Controller
@RequestMapping("/user")
public class UserController {
@Autowired
IUserService service;
@RequestMapping(value = "/login.do", method = {RequestMethod.GET})
public void login(User user) {
User result = service.login(user);
//登录是否成功就看result是否有返回值
System.out.println("判断登录是否成功" + result.getId());
}
}
@Repository
public interface UserMapper {
User findUser(@Param("user") User user);
}
public interface IUserService {
public User login(User user);
}
@Service //这时这个类就放进到了Spring的容器中
public class UserServiceImpl implements IUserService {
@Autowired
UserMapper mapper;
@Override
public User login(User user) {
return mapper.findUser(user);
}
}
<mapper namespace="com.home.test.mapper.UserMapper">
<resultMap id="UserType" type="com.home.test.entity.User" autoMapping="false">
<id property="id" column="id">id>
<result property="username" column="username">result>
resultMap>
<select id="findUser" resultMap="UserType">
select * from tb_fans where username = #{user.username} and pwd=#{user.pwd}
select>
mapper>
配置Spring的applicationContext.xml文件
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
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
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
">
<context:component-scan base-package="com.home.test">context:component-scan>
<bean id="dataSource" class="org.apache.ibatis.datasource.pooled.PooledDataSource">
<property name="driver" value="com.mysql.cj.jdbc.Driver">property>
<property name="url" value="jdbc:mysql://localhost:3306/db_foo?serverTimezone=UTC">property>
<property name="username" value="root">property>
<property name="password" value="zaq991221">property>
bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource">property>
<property name="mapperLocations" value="classpath:mapper/*.xml">property>
bean>
<bean id="mapperScanner" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.home.test.mapper">property>
bean>
beans>
部分内容参考:https://www.jianshu.com/p/91a2d0a1e45a