springMVC
内容管理
javaWeb—SSM中最后控制层MVC框架
SSM整合开发
昨天已经分享了返回值,还有@ResponstBody注解的数据可以直接输出到响应体;这里需要加上annotation-driven来避免和静态资源的resources、default-servlet-handler冲突;路径问题之前分析过,一般情况下,能用/就一定要用/;不加会变化
如果是jsp页面,为了可以使用/,这个时候可以使用EL表达式,{pageContext.request.cocntextPath}
; 之前使用servlet来写html代码的时候也是使用的request.getContextPath
昨天提到过,为了更方便的使用MVC解析资源,一般建立一个静态的目录static,将所有的静态资源放在下面,但是这样子就出现问题了,这里如果不加/,参考路径就会变成……/static/html
为了避免这些问题,如果是jsp页面,就可以使用EL表达式,如果是html,就可以使用base标签
base标签
base是html中的标签,因为前端一般使用的是不加/的方式,这个时候会自动以项目根路径的或者其他的作为参考路径,【欢迎页面比较特殊,因为地址栏不会显示完整的static/html/index.html;而是直接显示8080/MVCtest/ ----> 因此这里的参考路径就是最后一个/之前的 带上根路径;所以这里只是静态资源访问出现问题,如果是其他的html界面则还需要注意参考路径会变成static/html —>这个时候就要注意使用base】base就是表示当前页面访问地址的基地址。==页面中所有的不加/的地址,都是base指定的地址为参考地址,使用base中的地址 + 所写的地址,构成绝对地址
<!DOCTYPE html>
<html>
<head>
<!-- 为了能够正常访问动态资源,这里base设置到项目的根,和不加/的地址简单拼凑,所以要加上末尾加/ -->
<base href="http://localhost:8080/MVCtest/"/>
<meta charset="UTF-8">
<title>cfengOA.助力</title>
<script type="text/javascript" src="static/js/JQuery1.8.js"></script>
如果使用jsp还可以使用request内置对象动态得到地址
<%
String basePath = request.getScheme() + "://" + request.getServerName + ":" + request.getServerPort() + request.getContentPath + "/";
%>
<html>
<head>
<base href=<%= basePath %>/>
</head>
</html>
SSM整合开发
SSM也就是springMVC + spring + mybatis; SSH是springMVC + spring + hiberna;都差不多,除了基础的SSM,还有封装更复杂的SpringBoot;之后会提及这个框架。其实SSM整合的本质只是将spring整合入spring就可,SpringMVC就是spring;就多了一个配置文件而已;并且就是普通的spring配置文件;SSM再三层架构中分管不同的角色,SpringMVC主要是做控制层管理,Spring则是负责创建对象,当然SpringMVC就是Spring;主要就是使用的Spring中的@Controller注解,而普通的对象使用的是@Component进行创建,Spring主要的作用就是IOC和AOP; 而Mybatis是做持久层的操作,连接数据库
用户发起请求给SpringMVC接收 ----> spring中的service对象------>Mybatis处理数据
整合中出现了两个容器,一个是SpringMVC的容器,代替之前Tomcat的容器的作用;第二个是Spring的容器,就是service等对象存储的容器,使用的是全局监听器创建;把使用的对象交给合适的容器管理;SpringMVC容器是spring容器的子容器,使用一个spring主配置文件可以将所有的子容器整合为一个大的容器
springmvc容器就是spring容器的子容器,类似java中的继承,子可以访问父的内容
SSM整合实例
还是用一个小的实例来查看这个SSM整合的过程;这里还是使用学生表,就是cfengbase中的表student
mysql> SELECT * FROM student;
+-------+---------+----------+
| stuno | stuname | stuclass |
+-------+---------+----------+
| 1 | 张三 | HC2001 |
| 2 | 李四 | HC2002 |
| 3 | Cfeng | HC2002 |
| 4 | 王五 | HC2001 |
| 6 | Jning | HC2001 |
| 7 | 里斯 | HC2003 |
| 8 | 卡夫卡 | HC2004 |
| 10 | 里仁 | HC2004 |
| 11 | 小欢 | HC2006 |
| 12 | 黄某 | HC2001 |
| 13 | 奥利 | HC2002 |
| 14 | 新亚 | HC2003 |
+-------+---------+----------+
12 rows in set (0.04 sec)
maven建立一个web项目,导入依赖
mvc: 导入springMVC的依赖【会自动导入spring-context和spring-web】,加入servlet和jsp依赖,jackson依赖—jackson-core,jackson-bind
spring : 加入javax-annotatation-api依赖,druid依赖【连接池,整合mybatis】,spring-sapects【aop】,spring-tx,spring-jdbc【事务】
mybatis : 加入mybatis依赖,mysql驱动,mybatis-spring【整合】,pagehelper【分页】
junit依赖
以后开发差不多就是这些依赖,这里就将依赖都导入
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<!-- springMVC的依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.14</version>
</dependency><!--jsp的依赖,不需要tomcat了 -->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.1</version>
<scope>provided</scope>
</dependency>
<!--加入servlet依赖,(servlet的jar包) 不需要再配置tomcat了 -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
<!-- 加入jackson的依赖,数据转为json格式,包括core和datablind -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.13.1</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.13.1</version>
</dependency>
<!-- 添加mybatis依赖-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.9</version>
</dependency>
<!--添加mysql依赖 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.27</version>
</dependency>
<!-- 加入pageHelper依赖-->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.3.0</version>
</dependency>
<!-- 加入AspectJ依赖,方便实现AOP -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.3.13</version>
</dependency>
<!--spring transaction -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.3.14</version>
</dependency>
<!-- Spring jdbc-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.14</version>
</dependency>
<!-- mybatis 和spring集成-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.6</version>
</dependency>
<!-- 德鲁伊druid连接池-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.8</version>
</dependency>
</dependencies>
可以看到要完整开发项目,需要使用的jar包非常多,并且这些jar包各自还依赖其他的jar包,programmer自己管理非常复杂,所以maven真的减少了很多的复杂的工作
还有为了保证mapper文件正常加载到target/classes下,需要加入资源插件
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
<!-- 还要配置上原来编译资源的路径-->
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.*</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</build>
web.xml编写
- 注册DispatcherServlet : 创建springmvc容器对象,才能创建controller对象,创建的是servlet:才能接收用户的请求
- 注册spring容器的监听器,ContextLoaderListener, 创建Spring容器对象,才能创建service、dao等对象
- 注册字符过滤器CharacterEncodingFilter,【都是spring-web提供的】,解决post请求乱码的问题,创建放在mvc容器之前
<?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">
<!-- 注册字符过滤器 -->
<filter>
<filter-name>characterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<!-- 需要将参数设置: 编码方式,强制转换请求和响应 -->
<init-param>
<param-name>fileEncoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceRequestEncoding</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>forceResponseEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 注册中央调度器 -->
<servlet>
<servlet-name>DispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:conf/dispatcherServlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>DispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- 注册监听器 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- 指定监听器扫描的spring配置文件的位置 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:conf/applicationContext.xml</param-value>
</context-param>
<welcome-file-list>
<welcome-file>static/html/index.html</welcome-file>
</welcome-file-list>
</web-app>
中央调度器中需要注意init-param标签需要再load-on-startup之前,不然会出现一些问题,因为load是表明创建对象的时机的,一般放在最后面
创建包 — controller、service、dao、entity等
项目架构最重要的就是各司其职,所以各个不同功能的包要创建好
这里就简单将包创建好就可以,需要注意的是最好不要和其他模块的包冲突,这里就修改一下artificial就可以
编写springmvc、spring、mybatis的配置文件
springmvc、spring中主要就是要保证注解开发的正常进行,还有spring的配置文件要保证事务的正常进行,也要注册事务管理器等
配置文件直接全部放在resource下面会显得非常杂乱,所以这里就再建立一个conf目录,将资源放在conf目录下 < param-value>classpath:conf/dispatcherServlet.xml< /param-value>
- springMVC的配置文件编写是最简单的,【简单4个部分】需要一个组件扫描器识别@Controller —component-scan;再一个就是视图解析器用于解析处理器方法的视图 — 一个InternalResourceViewResolver对象bean创建;还有一个就是处理静态资源的,一般使用resources,因为不依赖Tomcat
<?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: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="Jning.controller"/>
<!-- 声明springmvc中的视图解析器,帮助开发人员设置视图文件的路径 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/view/"/>
<property name="suffix" value=".jsp"/>
</bean>
<!-- 和注解ResponseBodu配合使用,内部将对象转为json格式 -->
<mvc:annotation-driven/>
<!-- 解决静态资源覆盖问题,注册defaultServletHandler -->
<!-- <mvc:default-servlet-handler/>-->
<!-- 这里是后台路径,所以加上/,会带上根路径 location表示的是目录位置; mapping代表的是访问的url地址 -->
<mvc:resources mapping="/static/**" location="/static/"/>
</beans>
这里的组件扫描器的base-package就是controller即可,因为只是创建控制层的对象
视图解析器是为了方便书写视图路径,prefix和suffix分别制定视图的前缀和后缀,这样返回String的是时候只需要写逻辑名称
annotation-driven: 注解驱动,为了配合@ResourceBody;还有就是进行静态资源解析的时候避免冲突
还有就是静态资源解析的resources;或者使用default-servlet也可以,但是需要依赖tomcat服务器,是一个请求转发的过程
- 编写Mybatis主配置文件,这里将数据库剥离到druid中之后,mybatis的主配置文件的内容也就很少,必要的就3个部分,一个是设置环境,settings用来设置日志,第二个就是typaAilas设置别名,这样mapper文件中可以使用别名,别名就是类名;一般是实体类,最后一个最重要的就是mapper文件,和设置别名是类似的,也是使用package进行指定
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 配置日志信息,设置环境 -->
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
<!-- 设置别名,下面直接用包,不用一个一个用mapper指定,一般都是视实体类所在的包 -->
<typeAliases>
<package name="Jning.entity"/>
</typeAliases>
<!-- 以后的环境都是用druid了 -->
<!-- 设置映射文件的位置,这里和设置别名是类似的,这里直接指定包名就好了,一般就是dao包,因为mapper文件和接口放在一起,名称相同 -->
<mappers>
<!-- <mapper resource="cfeng\dao\StudentDao.xml"/> 直接按照包导入就可-->
<package name="Jning\dao"/>
</mappers>
</configuration>
注意:这里因为标签是用的/结尾,所以这里使用\; 这里的写法有两种,推荐使用上面的.的方式,下面的\必须要使用反斜杠
- 编写Spring配置文件,这里就有很多个部分,首先就是整合mybatis需要创建3个对象,datasource、sqlSessionFactory、dao
<?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">
<!-- spring 整合mybatis : 声明数据源对象,sqlSessionFactory对象,Dao对象 -->
<!-- 数据源对象,声明init和destroy的method代表的是创建和销毁连接池的方法,使用druid,其中要使用数据库的配置文件-->
<context:property-placeholder location="classpath:conf/db.properties"/>
<bean id="myDatasource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
<property name="password" value="${jdbc.password}"/>
<property name="username" value="${jdbc.user}"/>
<property name="url" value="${jdbc.url}"/>
<property name="maxActive" value="20"/>
</bean>
<!-- mybatis-spring为了整合提供的sqlSessionFactory对象,这里类型是加上Bean,创建sqlSession需要配置文件和datasource
因为之前是所有的都在mybatis主配置文件中,但是现在将数据库的信息,也就是environment交给了druid;对象的属性注入
-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="myDatasource"/>
<property name="configLocation" value="classpath:conf/mybatis.xml"/>
</bean>
<!-- 整合mybatis还需要的就是dao对象,这里使用的是扫描器对象,扫描mapper文件的,所以名称就是mapperScanner,
使用package为包扫描包下面所有的mapper文件,注意这是扫描配置文件,所以是configurer,不是bean
-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
<property name="basePackage" value="Jning.dao"/>
</bean>
<!-- 接下来就是声明组件扫描器,扫描service包下的对象注解,创建对象 -->
<context:component-scan base-package="Jning.service"/>
<!-- 完成spring的事务, 需要有事务的管理器,mybatis的是datasource,如果使用注解的方式,要用driven,如果使用aop的AspectJ也行 -->
<bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- 某个特定数据库的事务 -->
<property name="dataSource" ref="myDatasource"/>
</bean>
<!-- 如果使用注解就加入annotation-driven即可,指定扫描器;如果使用AspectJ,需要使用tx的advice指明通知method;可以通配
同时配置aop中的config,用来引入通知并且配置切入点表达式;因为上面的通知只有方法名,没有具体指明位置,这样advice才有效
-->
</beans>
这里的配置就要复杂一些了,事务可以简单使用注解,也可以使用AdpectJ,只是aspectJ需要tx的advice和aop的config来完成一个具体的通知
编写code、dao的结构和mapper文件等
这里就是要完成业务代码需要做的最主要的部分;前面就类似于就是一个项目的完整的结构,写代码这部分才是完成业务操作,就编写dao接口和mapper文件,同时编写service接口和实现类就可以了
这里是单表的查询非常简单
- dao接口
package Jning.dao;
import Jning.entity.Student;
import java.util.List;
public interface StudentDao {
public List<Student> selectAllStudents();
public int insertStudent(Student student);
}
- dao的mapper文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org/DTD Mapper 3.0" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="Jning.dao.StudentDao">
<select id="selectAllStudents" resultType="student">
SELECT stuno,stuname,stuclass FROM student ORDER BY stuno DESC
</select>
<insert id="insertStudent">
INSERT INTO student (stuname,stuclass) VALUES (#{stuname},#{stuclass})
</insert>
</mapper>
- 编写业务类的接口,命名就是之前业务的说明的类型
package Jning.service;
import Jning.entity.Student;
import java.util.List;
public interface StudentService {
public List<Student> queryStudents();
public int addStudent(Student student);
}
- 编写业务接口的实现类
package Jning.service.impl;
import Jning.dao.StudentDao;
import Jning.entity.Student;
import Jning.service.StudentService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
/**
* 这里需要创建业务类的对象,所以就直接使用@Service,不使用Component了
* 使用Resource进行自动注入
*/
@Service
public class StudentServiceImpl implements StudentService {
@Resource //这里首先byName,寻找同名
private StudentDao studentDao;
@Override
public List<Student> queryStudents() {
return studentDao.selectAllStudents();
}
@Override
public int addStudent(Student student) {
return studentDao.insertStudent(student);
}
}
- 编写控制器类型,这里只用一个就可以了
package Jning.controller;
import Jning.entity.Student;
import Jning.service.StudentService;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.UnsupportedEncodingException;
import java.util.List;
@Controller
@RequestMapping(value = "/student")
public class StudentAction {
@Resource //自动byName注入
private StudentService studentService;
@RequestMapping(value = "/addStudent",method = RequestMethod.POST)
public ModelAndView addStudent(Student student){
//定义处理结果返回对象
ModelAndView mv = new ModelAndView();
//调用service处理业务
String msg = "注册失败";
int num = studentService.addStudent(student);
if(num > 0){
msg = "学生【" + student.getStuname() + "】注册成功";
}
mv.addObject("msg",msg);
mv.setViewName("result");
return mv;
}
//使用ajax展示学生列表
@RequestMapping(value = "/queryStudent",method = RequestMethod.GET)
@ResponseBody
public List<Student> listStudent() {
//调用业务方法获取返回值
List<Student> list = studentService.queryStudents();
//annotation-driven直接自动调用jackson转为json
//注解过的对象直接返回给响应体
return list;
}
}
编写jsp等view界面
这里就简单编写一个jsp结果页面,需要注意的是,可能因为IDEA的不稳定问题,这里的过滤器有的时候会感觉不起作用,还有的时候将界面给乱码了,这个时候可以删除之后再次建立就可以成功进行了,并没有声明什么特殊的问题
//首先是一个index.html界面,ajax直接定义就可
<!DOCTYPE html>
<html>
<head>
<!-- 为了能够正常访问动态资源,这里base设置到项目的根,和不加/的地址简单拼凑,所以要加上末尾加/ -->
<base href="http://localhost:8080/MVCtest/"/>
<meta charset="UTF-8">
<title>cfengOA.助力</title>
<script type="text/javascript" src="static/js/JQuery1.8.js"></script>
<script type="text/javascript">
$(function() {
//点击按钮,按钮绑定一个ajax请求
$("#mybtn").click(function() {
$.ajax({
dataType: 'json',
url: 'student/queryStudent',
success: function (resp) {
var list = "<table><tr><th>学生学号</th><th>学生姓名</th><th>学生班级</th></tr>"
for(var i = 0; i < resp.length; i++) {
var student = resp[i];
list += "<tr><td>" + student.stuno + "</d>";
list += "<td>" + student.stuname + "</d>";
list += "<td>" +student.stuclass + "</d></tr>";
}
$("#mydiv")[0].innerHTML = list;
}
})
});
})
</script>
</head>
<body>
<h1 align="center">OA学生信息系统</h1>
<hr color="pink"/>
<a href="static/html/addStudent.html">添加学生</a><br/><br/><br/>
<input type="button" id="mybtn" value="查看学生列表"/><br/><br/><br/>
<div id="mydiv" style="font-size: large;color: aquamarine">学生列表信息……</div>
</body>
</html>
这里是简单使用js来进行的动态操作,其实这可以换成表的形式然后使用JQuery动态操作
$.ajax({
dataType: 'json',
url: 'student/queryStudent',
success: function (resp) {
$("#mytable").empty(); //删除所有的子对象
$("#mytable").append("<table><tr><th>学生学号</th><th>学生姓名</th><th>学生班级</th></tr>");
$.each(resp,function(index,student){
$("#mytable").append("<tr>").append("<td>").append(student.stuno).append("</td>")
.append("<td>").append(student.stuname).append("</td>")
.append("<td>").append(student.stuclass).append("</td>").append("</tr>")
}); //添加子标签
}
})
});
<table id="mytable" bgcolor="aquamarine" bordercolor="pink"></table>
这样一个简单的SSM流程就开发完成了,简单来说,框架真的简化了很多东西,特别是数据库的连接部分,还有service和controller的DI和AOP等都很方便
这里要加入业务也很简单,使用AspectJ框架即可,使用annotation-driven和一个aop的config就可以完成操作
<!-- 完成spring的事务, 需要有事务的管理器,mybatis的是datasource,如果使用注解的方式,要用driven,如果使用aop的AspectJ也行 -->
<bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- 某个特定数据库的事务 -->
<property name="dataSource" ref="myDatasource"/>
</bean>
<!-- 如果使用注解就加入annotation-driven即可,指定扫描器;如果使用AspectJ,需要使用tx的advice指明通知method;可以通配
同时配置aop中的config,用来引入通知并且配置切入点表达式;因为上面的通知只有方法名,没有具体指明位置,这样advice才有效
-->
<!-- id自定义,表示配置内容-->
<tx:advice id="myadvise" transaction-manager="dataSourceTransactionManager">
<tx:attributes> <!--表示要配置的事务的属性 method是作用的方法,切入点 -->
<tx:method name="add*" propagation="REQUIRED" isolation="DEFAULT"
rollback-for="java.lang.NullPointerException"/>
</tx:attributes>
</tx:advice>
<!-- 配置aop -->
<aop:config>
<!-- 配置切入点表达式,指出哪些类需要应用事务 id 切入点表达式的名称 切入点表达式:指出切入点表达式-->
<aop:pointcut id="servicePt" expression="execution(* *..service..*.*(..))"/>
<!-- 配置增强器: 关联pointcut和上面的advisce -->
<aop:advisor advice-ref="myadvise" pointcut-ref="servicePt"/>
</aop:config>
这里就是为添加操作给加入了事务,这样添加学生的时候查看控制台的日志
Transaction synchronization committing SqlSession ---> 成功添加学生,提交事务
SpringMVC将之前的servlet的请i去转发和重定向的操作都进行了封装,可以使用更加简单的方式实现重定向和请求转发。 forward表示转发,实现执行的forword;redirect表示重定向,实现之前的response.sendRedirect();
需要注意的是: 对于请求转发的页面,可以是WEB-INF的页面,因为是浏览器来进行调用,而重定向的页面是不能使WEB-INF下面的,因为重定向可以看作是用户再次发了一次请求; 但是两者的共同点就是都是不和视图解析器一起工作
MVC请求转发和重定向【避免视图解析】
请求转发
处理器方法返回ModelAndView的时候,需要在setViewName中指定视图前面添加forward,这个时候的视图不再会使用视图解析器,这样就可以指定不同的视图,不再遵循视图解析器的规则
;视图页面里是后台路径,也就是相对于项目的根路径,forward操作不需要视图解析器
这里来实现这个测试请求转发,首先前端页面简单编写一个表单
方法返回值为modelAndView的时候实现请求转发
<br><br>
方法返回值为modelAndView的时候实现请求转发
<form action="/test/some.do" method="post">
用户名<input type="text" name="user"/><br>
年龄<input type="text" name="age"/><br>
<input type="submit" value="注册"/>
</form>
这里返回值是ModelAndView的时候才能使用请求转发,因为ModelAndView的底层就是进行请求转发,但是只是没有指明而已,要使用请求转发,只用在setViewName里加上forward和视图完整路径就可以 【不管资源在哪里都行,WEB-INF】
//格式
mv.setViewName("forward:视图完整路径")
不和视图解析器一同工作,就相当于项目中没有视图解析器
package Jning.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;
@Controller
@RequestMapping(value ="/test")
public class RedirctTest {
@RequestMapping(value ="/some.do",method = RequestMethod.POST)
public ModelAndView doSome(String user,int age) {
System.out.println(user + ": " + age);
ModelAndView mv = new ModelAndView();
mv.setViewName("forward:/test.html");
return mv;
}
}
视图解析器解析的都是WEB-INF/view下面的jsp文件,这里想要访问不再这里的文件,就只能使用forward: 这是一种显式转发,可以帮助转发到任意的位置【但是和之前的servlet的相同,浏览器的地址还是最开始访问的地址就是some.do,并且不能跨项目重定向】
重定向
重定向也和请求转发相同处理视图的路径的,也是可以让视图解析失效,这里使用的格式和上面的相同显式表达就可以了
mv.setViewName("redirect:XXX")
重定向的问题和之前的servlet的问题都是相同的:
- 注意重定向相当于时用户发了多次请求,重定向的地址栏路径就是最终访问的路径,需要注意的是因为HTTP协议是无状态的,所以之前的请求域中的数据是不能正常传递的,这个时候要继续传递数据,只能能够拼URL的规则,将数据通过类似GET的形式传递参数
- 重定向是不能访问WEB-INF下面的数据的,因为这不是服务器内部转发,而是在浏览器外面进行转发,所以不能访问服务器内部资源
package Jning.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;
@Controller
@RequestMapping(value ="/test")
public class RedirctTest {
@RequestMapping(value ="/some.do")
public ModelAndView doSome(String user,int age) {
System.out.println(user + ": " + age);
ModelAndView mv = new ModelAndView();
mv.setViewName("redirect:/test.html");
return mv;
}
}
这里和上面的结果是相同的,需要注意的是,这里相当于是两个请求,所以不能使用请求域中的数据🎄