声明式事务
开发者采用配置的方式来实现事务的控制,业务代码和事务代码实现解耦合,使用的就是上一篇的AOP思想。
都需要定义一个事务管理器,都需要导入spring-aop和aspectjweaver两个jar包
事务的传播行为
事务传播行为指的就是当一个业务方法被另一个业务方法调用时,应该如何进行事务控制。
业务层A方法,调用业务层B方法【主要角色】
* REQUIRED【必须】默认值 运行的时候必须有事务
A方法调用B方法,如果A方法没有事务,B方法创建一个事务,如果A方法有事务,那么B方法直接使用A方法的事务控制
* SUPPORTS【支持】运行的时候 有就用 没有就不用
A方法调用B方法,如果A方法没有事务,B方法也没有事务,如果A方法有事务,那么B方法直接使用A方法的事务控制
1.xml配置声明式事务
需求
使用spring声明式事务控制转账业务。
步骤分析:
在applicationContext.xml中
- 配置事务管理器 因为dao使用的JDBCTemplate,所以事务管理器为:DataSourceTransactionManager,注入连接池
- 定义事务的运行状态,通过tx标签配置
就是给某种方法设置隔离级别,传播行为,是否只读,超时时间等 - aop配置,给那些切点配置spring提供好的事务通知.
db.propeties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/springtest
jdbc.username=root
jdbc.password=1234
applicationContext.xml
<context:property-placeholder location="db.properties"/>
<context:component-scan base-package="com.llz"/>
<!--配置数据源-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!--配置jdbcTempalte-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--配置事务管理器,id建议大家使用transactionManager-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--注入数据源-->
<property name="dataSource" ref="dataSource"/>
</bean>
<!--tx:advice标签配置运行规则
给某种方式设置隔离级别,传播行为,是否只读,超时时间
id属性:起个名字,待会用
transactionManager属性:指定使用那个事务管理器,若事务管理器的名字为transactionManager的话,此属性可以省略
-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!--以find开头的方方法,使用默认的隔离级别,使用supports传播行为,只读,超时时间为默认值:永不超时-->
<tx:method name="find*" isolation="DEFAULT" propagation="SUPPORTS" read-only="true" timeout="-1"/>
<!--其他方法,使用默认的属性,用默认的隔离级别,默认传播行为,不是只读事务,超时时间为默认值-->
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
<!--aop配置-->
<aop:config>
<!--切入点-->
<aop:pointcut id="pc" expression="execution(* com.llz.service..*.*(..))"/>
<!--切面,使用spring已定义好的通知类-->
<aop:advisor advice-ref="txAdvice" pointcut-ref="pc"/>
</aop:config>
2.注解+xml配置声明式事务
步骤分析:
- 修改上面的applicationContext.xml
- 删除事务控制的tx标签和aop标签
- 添加事务的注解支持
- 在service类上或者service中方法上添加注解@Transactional
- 可以通过注解的属性配置隔离级别,传播行为,是否只读,超时时间
<!--开启事务注解支持-->
<tx:annotation-driven transaction-manager="transactionManager"/>
注意:若使用注解的话,千万记住要给每个service或者service中的方法添加注解
3.纯注解(了解即可,项目上一般不会使用)
步骤分析:
- 编写配置类 SpringConfig,添加注解,替代applicationContext.xml
- 声明注解是一个配置类
- 组件扫描
- 加载properties配置文件
- 事务注解支持
- 创建数据源加入spring管理
- 创建jdbcTemplate加入spring管理
- 创建事务管理器,加入spring管理
主配置类:
@Configuration
@ComponentScan("com.llz")
@PropertySource("classpath:db.properties")
@EnableTransactionManagement//开启事务注解支持
@Import({DaoConfig.class,ServiceConfig.class})//引入其他的配置类
public class SpringConfig {
}
其他配置类:
public class DaoConfig {
@Value("${jdbc.driver}")
private String driver;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
/*创建数据源,加入spring管理*/
@Bean
public DataSource createDS(){
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName(driver);
ds.setUrl(url);
ds.setUsername(username);
ds.setPassword(password);
return ds;
}
/*创建jdbcTemplate,加入spring管理*/
@Bean
public JdbcTemplate createJdbcTemplate(DataSource dataSource){
return new JdbcTemplate(dataSource);
}
}
public class ServiceConfig {
/*创建事务管理器*/
@Bean
public PlatformTransactionManager createTXManager(DataSource dataSource){
return new DataSourceTransactionManager(dataSource);
}
}
SpringMVC
1.简介
springMVC是按照MVC设计模式开发的轻量级web框架,他也是spring家族的一部分。
springMVC封装了servlet公共的特性,使开发者只需要关注业务的私有特性,来提高开发效率。
要想处理公共的特性,应该能获取到request和response对象(前端控制器).谁能获取到这两个对象
- servlet:例如springmvc使用DispatcherServlet
- filter:例如struts2使用StrutsPrepareAndExecuteFilter
使用springmvc的时候,需要先配置好前端控制器,然后就可以使用普通javabean处理业务请求
快速入门
在index.jsp上有一个连接(/springmvc/hello),点击连接,在控制台打印一句话,转发到/WEB-INF/pages/success.jsp
步骤分析
- 新建web项目,导入依赖(servlet,jsp,spring-webmvc)
- 编写index和success.jsp
- 编写一个普通的类 例如:HelloController
- 编写一个普通的方法,例如:sayHello
- 返回值string类型:目前就要转发的路径
- 在类上添加注解@Controller,交给springmvc容器管理
- 在方法上添加注解@RequestMapping(“hello”),将请求的路径和目标方法形成映射关系
- 编写一个普通的方法,例如:sayHello
- 在resources编写springmvc的核心配置文件,名字随意,建议叫springmvc.xml
- 组件扫描
- 开启springmvc的注解支持
- 配置视图解析器
- 在web.xml配置前端控制器
- 配置DispatcherServlet
- 配置springmvc核心配置文件的路径
- 配置servlet的加载时机 load-on-startup
- 配置servlet的映射路径 /
- 配置DispatcherServlet
- 测试
代码实现
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.2</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
controller类:
@Controller
public class A_HelloController {
@RequestMapping("hello")
public String sayHello(){
System.out.println("收到了请求");
//配置了视图解析器之后,返回的字符串就是转发的视图名称
return "success";
//return "/WEB-INF/pages/success.jsp";
}
}
springmvc.xml:
<!--开启组件扫描-->
<context:component-scan base-package="cn.it.web"/>
<!--开启mvc注解支持-->
<mvc:annotation-driven/>
<!--配置视图解析器对象-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!--配置前缀-->
<property name="prefix" value="/WEB-INF/pages/"/>
<!--配置后缀-->
<property name="suffix" value=".jsp"/>
</bean>
web.xml
<!--配置springmvc的前端控制器-->
<servlet>
<servlet-name>DispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--指定springmvc核心配置文件路径-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<!--修改servlet的初始化时机-->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>DispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!--配置字符编码过滤器(post请求中文过滤器)-->
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<!--指定post请求的编码-->
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
执行流程
SpringMVC组件概述
SpringMVC框架执行流程(重点)
项目启动时:
- dispatcherServlet对象就会随着项目的启动完成创建操作
- 读取核心配置文件,创建springmvc容器对象
- 扫描cn.it.web包下所有的带有@Component及其衍生注解的类,创建对象,加入springmvc容器中
- 扫描有@RequestMapping的方法,将访问路径和类名+方法形成映射关系
- 创建视图解析器对象,加入到springmvc容器中
请求来的时候:
- 当请求来的时候,路径为:/hello,前端控制器就会收到这个请求
- 前端控制器就找到处理器映射器,问它:/hello对应是哪个类中哪个方法. 处理器映射器返回:要执行的A_HelloController中的sayHello方法,没有拦截器
- 前端控制器再找到处理器适配器,告诉它:去执行A_HelloController中的sayHello方法.
- 处理器适配器获取到A_HelloController对象(处理器),让其调用它的sayHello方法.
- 处理器执行后,返回字符串"success".
- 处理器适配器拿到字符串之后,将返回的数据和字符串封装到ModelAndView对象中,返回给前端控制器
- 前端控制器拿到ModelAndView之后,获取视图字符串"success",找到视图解析器,问:success对象的是那个jsp(视图)
- 视图解析器拿到"success"之后,拼接前缀,字符串,后缀,生成视图对象(物理视图),返回给前端控制器
- 前端控制器拿到物理视图之后,将model放入指定域中,转到物理视图(success.jsp)
- jsp执行后,生成html代码.将html代码返回给前端控制器
- 前端控制器将html代码写回给浏览器
三大组件
处理器映射器、处理器适配器、视图解析器
* 前端控制器
整个流程控制的中心,由它调用其它组件处理用户的请求
* 处理器映射器(mvc支持注解)
负责将url路径和方法上的路径产生映射关系,返回处理器执行链
* 处理器适配器(mvc支持注解)
根据执行路径查找多个处理器中的某一个方法,执行业务逻辑,返回ModelAndView
* 视图解析器
将逻辑视图解析(例如:success)为view对象(真实资源文件对象)
请求常用的注解解析
@Controller
- 作用在web层的类上,将类对应的对象加入springmvc容器中(IOC)
@RequestMapping - 主要作用:配置路径和方法的映射. 该注解可以作用类上和方法上
- 常用或常见属性:
- value属性:
- 若类上也有此注解,类上的value就是一级路径,方法上的路径就是二级路径.最终访问路径就是一级路径+二级路径.方便团队模块开发
- name属性:给处理器起个名字
- params属性:规定请求的路径中必须出现的参数内容,若没有报400异常
- method属性:规定处理哪种请求方式
- value属性:
@Controller
@RequestMapping("mapping")//mapping就是一级路径
public class B_ReqeustMappingController {
/*
* name属性:给处理器起个名字
* params属性:规定请求的路径中必须出现的参数内容,若没有报400异常
*/
@RequestMapping(value = "test1",name = "测试name属性",params = "username")
public String test1(){
System.out.println("收到了请求");
return "success";
}
/*
* method属性:规定处理哪种请求方式,只处理get和post
*/
@RequestMapping(value = "test2",method = {RequestMethod.POST,RequestMethod.GET})
public String test2(){
System.out.println("收到了请求");
return "success";
}
}
@RequestParam
- 主要作用:当请求参数和方法参数名称不一样的时候,将请求的参数和方法参数形成映射关系. 它还可以设置参数的默认值
-
value属性:将请求参数的数据绑定到方法中某个参数上 defaultValue属性:给参数设置默认值.当此参数没有值的时候就会使用默认值
@RequestMapping("anno")
public class D_AnnoController {
/*
@RequestParam
value属性:将请求参数的数据绑定到方法中某个参数上
defaultValue属性:给参数设置默认值.当此参数没有值的时候就会使用默认值
*/
@RequestMapping(value = "test1")
public String test1(@RequestParam(value="pageNumber") int pageNum, @RequestParam(defaultValue = "5") int pageSize){
System.out.println(pageNum+"-"+pageSize);
return "success";
}
}
SpringMVC的响应
1.响应方式介绍
方法的返回值:
- string
- 默认就是转发
- 使用关键字声明转发还是重定向
- void
- 一般就是使用servlet原生的api进行操作,在文件下载中常用
- modelAndView
- 放置数据到域中,转发或者重定向都可以
String返回
a.默认方式
就是转发操作.若想往request域中存放数据,可以通过原生的servlet方式操作或者springmvc中的方式进行操作
- springmvc方式中,可以通过map、modelMap或者model都可以
//默认转发
@RequestMapping("test1")
public String test1(HttpServletRequest request, Map map, ModelMap modelMap, Model model){
//往request域中存放数据
request.setAttribute("requestKey",1);
map.put("mapKey",2);
modelMap.put("modelMapKey",3);
model.addAttribute("modelKey",4);
return "success";
}
b.转发和重定向
可以在返回值前面加上关键字声明转发还是重定向,一旦使用了关键字,就不再使用视图解析器
- forward: 转发 后面跟上就是转发的内部路径
- redirect: 重定向
- 站内资源 后面跟上内部路径
- 站外资源 后面跟上url
//关键字转发
@RequestMapping("test2")
public String test2(Map map){
map.put("mapKey","关键字转发过来的数据");
return "forward:/WEB-INF/pages/success.jsp";
}
//关键字重定向
@RequestMapping("test4")
public String test4(){
return "redirect:http://www.baidu.com";
}
c.void返回
一般就是使用原生的api做文件下载操作.也不走视图解析器
@Controller
@RequestMapping("void")
public class B_VoidController {
//void返回值做转发
@RequestMapping("test1")
public void test1(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setAttribute("requestKey","void转过的数据");
request.getRequestDispatcher("/WEB-INF/pages/success.jsp").forward(request,response);
}
//void返回值做重定向
@RequestMapping("test2")
public void test2(HttpServletRequest request, HttpServletResponse response) throws IOException {
response.sendRedirect(request.getContextPath()+"/html/1.html");
}
}
d.ModelAndView返回
方式一:在方法中创建对象
方式二:在方法的参数上声明对象
@Controller
@RequestMapping("mv")
public class C_ModelAndViewController {
@RequestMapping("test1")
public ModelAndView test1(ModelAndView mv){
//往域中存放数据
mv.addObject("modelKey","mv转发过来的数据");
//设置转发的路径
mv.setViewName("success");
return mv;
}
@RequestMapping("test2")
public ModelAndView test2(){
ModelAndView mv = new ModelAndView();
//往域中存放数据
mv.addObject("modelKey","mv转发过来的数据");
//设置转发的路径
mv.setViewName("forward:/WEB-INF/pages/success.jsp");
return mv;
}
}
@RequestBody
将请求的json数据封装成指定对象
@ResponseBody
将方法的返回值转成json字符串写回浏览器
@RequestMapping("test2")
//RequestBody : 将请求的json数据封装成指定对象
//ResponseBody : 将方法的返回值转成json字符串写回浏览器
@ResponseBody
public Map test2(@RequestBody User user, HttpServletResponse response) throws IOException {
System.out.println(user);
Map map = new HashMap();
map.put("success",true);
map.put("msg","用户名:"+user.getUsername());
return map;
}
RESTful(重要)
restful是一种软件架构的设计风格。主要用于客户端和服务器交互的软件架构。如果我们软件设计使用了此风格,咱们的架构层次更加分明,简洁、易于缓存…
通过请求路径+请求方式来简化路径编写,确定要指定的是那个controller
- 查询操作 请求路径:/user/id值 请求方式:get
- 删除操作 请求路径:/user/id值 请求方式:delete
- 保存操作 请求路径:/user 请求方式:post
- 更新操作 请求路径:/user 请求方式:put
浏览器提交的方式只能为二种:get、post
使用ajax发送不同的请求方式即可.
spring提供的注解:
- @PathVariable(“uid”) :获取请求路径上变量赋值给方法参数
- @GetMapping(“路径”):处理get请求的requestMapping
- @PostMapping(“路径”)
- @DeleteMapping(“路径”)
- @PutMapping(“路径”)
- @RestController 一个顶俩(@Controller和@ResponseBody)
<input type="button" value="f_查询" id="btn_get">
<input type="button" value="f_删除" id="btn_delete">
<input type="button" value="f_保存" id="btn_post">
<input type="button" value="f_更新" id="btn_put">
<%--导入jquery.js--%>
<script src="js/jquery-2.2.3.min.js"></script>
<script>
/*restful*/
//查询
$("#btn_get").click(function () {
$.ajax({
url:"${pageContext.request.contextPath}/user/10",
type:"get",
success:function (resp) {
if (resp.success) {
alert(resp.msg);
}
}
})
});
//删除
$("#btn_delete").click(function () {
$.ajax({
url:"${pageContext.request.contextPath}/user/9",
type:"delete",
success:function (resp) {
if (resp.success) {
alert(resp.msg);
}
}
})
});
//保存
$("#btn_post").click(function () {
$.ajax({
url:"${pageContext.request.contextPath}/user",
type:"post",
data:"username=tom&age=18",
success:function (resp) {
if (resp.success) {
alert(resp.msg);
}
}
})
});
//更新
$("#btn_put").click(function () {
$.ajax({
url:"${pageContext.request.contextPath}/user",
type:"put",
data:"username=jack&age=19",
success:function (resp) {
if (resp.success) {
alert(resp.msg);
}
}
})
});
</script>
//@Controller
//@ResponseBody //可以作用在类上和方法上
@RestController //一个顶俩(@Controller和@ResponseBody )
public class F_UserController {
/*
* @PathVariable:将路径上的指定名称变量绑定到方法的参数上
* @GetMapping:处理get请求RequestMapping
* @DeleteMappping:处理delete请求RequestMapping
* @PutMapping:处理put请求RequestMapping
* @PostMapping:处理post请求RequestMapping
*/
//@RequestMapping(value="user/{uid}",method = RequestMethod.GET)
@GetMapping("user/{uid}")//相当于@RequestMapping(value="user/{uid}",method = RequestMethod.GET)
//@ResponseBody
public Map findById(@PathVariable("uid") int id){
System.out.println(id);
Map map = new HashMap();
map.put("success",true);
map.put("msg","获取指定的用户,id为:"+id);
return map;
}
@DeleteMapping("user/{uid}")
public Map deleteById(@PathVariable("uid") int id){
System.out.println(id);
Map map = new HashMap();
map.put("success",true);
map.put("msg","删除指定的用户,id为:"+id);
return map;
}
@PostMapping("user")
public Map save(User user){
System.out.println(user);
Map map = new HashMap();
map.put("success",true);
map.put("msg","保存用户,username:"+user.getUsername());
return map;
}
@PutMapping("user")
public Map update(User user){
System.out.println(user);
Map map = new HashMap();
map.put("success",true);
map.put("msg","修改用户,username:"+user.getUsername());
return map;
}
}