SSM框架学习第三天
Spring事务
事务作用:在数据层保障一系列的数据库操作同成功或同失败
Spring事务:在数据层和业务层保障了一系列的数据库操作同成功同失败
Spring事务实现:
Spring提供了PlatformTransactionManager接口,实现Spring事务的实现。
Spring还提供了一个DataSourceTransactionManager实现类,但是这个实现类的内部实现是用JDBC的,只有用JDBC才能用这个实现类来实现事务。
案例
模拟银行转账
用事务实现同成功或者同失败。
实现:
dao层代码
package com.lwg.dao;
import com.lwg.pojo.Deposit;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Update;
import org.springframework.stereotype.Repository;
@Repository
public interface DepositDao {
@Update("UPDATE deposit SET balance=balance+100.0 WHERE id=#{id}")
public int addMoney(@Param("id") int id, @Param("money") double money);
@Update("UPDATE deposit SET balance=balance-#{money} WHERE id=#{id}")
public int reduceMoney(@Param("id") int id, @Param("money") double money);
@Insert("INSERT INTO deposit(NAME,balance) VALUES(#{name},#{balance})")
public int addUser(Deposit deposit);
}
(1)开启事务,关键词@Transactional
service层代码
package com.lwg.service;
import com.lwg.dao.DepositDao;
import com.lwg.pojo.Deposit;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.beans.Transient;
@Service
public class DepositService {
@Autowired
private DepositDao depositDao;
@Transactional //开启事务
public void transfer(int outId,int inId,double money){
System.out.println(money);
int i=depositDao.addMoney(inId,money);
System.out.println(i);
int g=1/0; //会报错,从而导致前面的操作成功,后面操作失败
int i1 = depositDao.reduceMoney(outId, money);
System.out.println(i1);
}
public void addDeposit(Deposit deposit){
int i = depositDao.addUser(deposit);
System.out.println(deposit);
System.out.println(i);
}
}
(2)定义事务
创建Bean交由spring管理。
在jdbc配置类中配置Bean
@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource){
DataSourceTransactionManager transactionManager=new DataSourceTransactionManager();
transactionManager.setDataSource(dataSource);
return transactionManager;
}
(3)在spring配置类中定义使用注解方式使用事务
spring配置类代码
package com.lwg.config;
import org.springframework.context.annotation.*;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@Configuration
@ComponentScan("com.lwg")
@PropertySource("jdbc.properties")
@Import({JdbcConfig.class,MybatisConfig.class})
@EnableTransactionManagement //注解方式使用事务
public class SpringConfig {
}
Spring事务角色
Spring事务相关配置
以上属性都可以用注解方式进行配置
格式:
@Transactional(readOnly = true,timeout = -1)
**事务传播行为:**事务协调员对事务管理员所携带事务的处理态度,通俗讲就是我的事务加不加入你开的事务里,是否和你同一个事务,也就是是否和你同成功或者同失败。
实现事务传播行为
@Transactional(propagation = Propagation.REQUIRES_NEW) //事务传播行为,我自己一个事务,不和你同一个事务
propagation属性值:
案例:
使用事务传播行为实现需求
代码实现:
准备日志表和日志实体类
日志表sql语句:
CREATE TABLE `user_log` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`info` text,
`create_date` char(16) DEFAULT NULL,
`result` char(1) DEFAULT NULL COMMENT '0成功,1失败',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=utf8
日志实体类:
package com.lwg.pojo;
import com.lwg.config.SpringConfig;
public class UserLog {
private int id ;
private String info;
private String createDate;
private String result;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getInfo() {
return info;
}
public void setInfo(String info) {
this.info = info;
}
public String getCreateDate() {
return createDate;
}
public void setCreateDate(String createDate) {
this.createDate = createDate;
}
public String getResult() {
return result;
}
public void setResult(String result) {
this.result = result;
}
@Override
public String toString() {
return "UserLog{" +
"id=" + id +
", info='" + info + '\'' +
", createDate='" + createDate + '\'' +
", result='" + result + '\'' +
'}';
}
}
dao层:
package com.lwg.dao;
import com.lwg.pojo.UserLog;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Result;
import org.apache.ibatis.annotations.ResultMap;
import org.apache.ibatis.annotations.Results;
import org.springframework.stereotype.Repository;
@Repository
public interface LogDao {
@Insert("INSERT INTO user_log(id,info,create_date,result) VALUES(#{id},#{info},#{createDate},#{result})")
@Results(id="logMap",value = {
@Result(property ="createDate",column ="create_date")
})
public int insertLog(UserLog userLog);
}
service层
package com.lwg.service;
import com.lwg.dao.LogDao;
import com.lwg.pojo.UserLog;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
@Service
public class LogService {
@Autowired
private LogDao logDao;
@Transactional(propagation = Propagation.REQUIRES_NEW) //事务传播行为,我自己一个事务,不和你同一个事务
public int addLog(UserLog userLog){
return logDao.insertLog(userLog);
};
}
修改上面那个转账案例的service层
package com.lwg.service;
import com.lwg.dao.DepositDao;
import com.lwg.pojo.Deposit;
import com.lwg.pojo.UserLog;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import java.beans.Transient;
import java.text.SimpleDateFormat;
import java.util.Date;
@Service
public class DepositService {
@Autowired
private DepositDao depositDao;
@Autowired
private LogService logService;
@Transactional(timeout = -1) //开启事务
public void transfer(int outId,int inId,double money){
String retlut="1";
try {
System.out.println(money);
int i=depositDao.addMoney(inId,money);
System.out.println(i);
// int g=1/0;
int i1 = depositDao.reduceMoney(outId, money);
System.out.println(i1);
retlut="0";
}finally {
Deposit inDeposit = selectById(inId);
Deposit outDeposit = selectById(outId);
String inName = inDeposit.getName();
String outName = outDeposit.getName();
System.out.println(outName);
System.out.println(inName);
String info=outName+"向"+inName+"转账"+money+"元";
System.out.println(info);
System.out.println(retlut);
SimpleDateFormat sdf =new SimpleDateFormat("yyyy-MM-dd HH:mm");
String newDate = sdf.format(new Date());
UserLog userLog=new UserLog();
userLog.setCreateDate(newDate);
userLog.setInfo(info);
userLog.setResult(retlut);
logService.addLog(userLog);
}
}
public void addDeposit(Deposit deposit){
int i = depositDao.addUser(deposit);
System.out.println(deposit);
System.out.println(i);
}
public Deposit selectById(int id){
return depositDao.selectById(id);
}
}
SpringMVC
简介
SpringMVC是一种基于Java实现MVC模型的轻量级web框架
SpringMVC是Spring的一部分,SpringMVC和JavaWeb中的Servlet技术功能等同,用于web层开发,优点就是相同功能SpringMVC用更少的代码。
入门案例
(1)导包
导servlet、springMVC
<!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
(2)定义一个表现层Bean
@Controller 表现层Bean注解
package com.lwg.controller;
import org.apache.ibatis.annotations.Results;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class Demo1Controller {
@RequestMapping("/demo1") //请求路径
@ResponseBody
public String demo1(){
System.out.println("user SpringMVC");
return "{msg:user SpringMVC}"; //返回请求
}
}
(3)初始化SpringMVC,实现SpringMVC配置类,设定SpringMVC加载Bean对应的路径
package com.lwg.config;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Controller;
@Configuration
@ComponentScan("com.lwg.controller")
@EnableWebMvc //开启json数据转换成对象的功能
public class SpringMvcConfig {
}
(4)定义一个servlet容器启动配置类,初始化servlet容器,加载SpringMVC环境,并设置SpringMVC技术处理的请求
package com.lwg.config;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.support.AbstractDispatcherServletInitializer;
public class ServletContinerslnerslnitConfig extends AbstractDispatcherServletInitializer {
//加载SpringMVC容器配置
@Override
protected WebApplicationContext createServletApplicationContext() {
AnnotationConfigWebApplicationContext acx=new AnnotationConfigWebApplicationContext();
acx.register(SpringMvcConfig.class);
return acx;
}
//设置哪些请求归SpringMVC处理
@Override
protected String[] getServletMappings() {
return new String[]{"/"}; //所有请求
}
// 加载spring容器配置
@Override
protected WebApplicationContext createRootApplicationContext() {
AnnotationConfigWebApplicationContext acx=new AnnotationConfigWebApplicationContext();
acx.register(SpringConfig.class);
return acx;
}
}
运行结果:
在spring配置类加载Bean时如何限制不加载springMVC加载的Bean
第一种方法,我加载的路径下包含了SpringMVC加载的Bean,去掉SpringMVC加载的Bena。
//@ComponentScan("com.lwg")
@ComponentScan(
value = "com.lwg",
//排除指定注解方式的Bean
excludeFilters =@ComponentScan.Filter(
type = FilterType.ANNOTATION,
classes = Controller.class
)
)
第二种方式,精准加载,spring加载Bean写精准路径。
@ComponentScan({"com.lwg.dao","com.lwg.service"})
简化第四步的Servlet容器类的配置信息
package com.lwg.config;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
import org.springframework.web.servlet.support.AbstractDispatcherServletInitializer;
/*public class ServletContinerslnerslnitConfig extends AbstractDispatcherServletInitializer {
//加载SpringMVC容器配置
@Override
protected WebApplicationContext createServletApplicationContext() {
AnnotationConfigWebApplicationContext acx=new AnnotationConfigWebApplicationContext();
acx.register(SpringMvcConfig.class);
return acx;
}
//设置哪些请求归SpringMVC处理
@Override
protected String[] getServletMappings() {
return new String[]{"/"}; //所有请求
}
// 加载spring容器配置
@Override
protected WebApplicationContext createRootApplicationContext() {
AnnotationConfigWebApplicationContext acx=new AnnotationConfigWebApplicationContext();
acx.register(SpringConfig.class);
return acx;
}
}*/
//简化
public class ServletContinerslnerslnitConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[]{SpringConfig.class};
}
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{SpringMvcConfig.class};
}
@Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
}
请求与响应
请求映射路径
接收参数
普通参数的获取
定义方法的形参类型和名字和参数的类型名字一致即可。无论是get还是post请求都是这个方法获取参数。
例:获取参数为name、ager.
处理获取参数中文乱码
添加过滤器,在servlet容器类中添加
//添加过滤器
@Override
protected Filter[] getServletFilters() {
CharacterEncodingFilter filter=new CharacterEncodingFilter(); //编码格式过滤器类
filter.setEncoding("UTF-8"); //设置编码格式
return new Filter[]{filter};
}
当形参名与请求传过来的参数名不一致时,上面是获取不到的,可用@RequestParam注明参数名
形参名直接用实体类aojo类对象,当请求传进来的参数名与对象属性名一致会自动封装进对象。
当参数有多个值时,比如复选框,形参为数组即可接收到参数。
也可以集合获取
接收json数据
(1)jons数据为集合
传的json数据:
获取参数要用@RequestBody
(2)json数据为pojo对象,是对象类型
传的josn数据
使用关键词@RequestBody,传的Json数据字段名和对象属性名一致就会自动封装在对象里。
(3)json数据是对象数组
传的josn数据
使用关键词@RequestBody
日期参数接收,可以直接使用Data类的对象接收,会自动转换,日期格式有默认格式,当格式不一致要使用关键词@DateTimeFormat(pattern = “日期格式”),默认格式是yyyy/MM/dd
y:年 M:月 d:日 H:小时 m:分 s:秒
响应
(1)响应页面,即响应跳转页面
直接返回页面路径即可
(2)返回文本数据,要使用@ResponseBody注解
(3)返回json格式数据
直接返回返回的数据就可以了,无论是数组、还是pojo对象,还是列表,会自动转成json数据返回。
REST风格
描述访问资源的形式
这种形式称为RESTful,这种开发风格称为REST风格
入门案例
package com.lwg.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class UserController {
//查询所有
@RequestMapping(value = "/users",method = RequestMethod.GET)
@ResponseBody
public String allData(){
System.out.println("查询所有,使用get请求,不带路径参数");
return "all";
}
//查询单个
@RequestMapping(value = "users/{id}",method = RequestMethod.GET)
@ResponseBody
//使用@PathVariable指明这是路径参数,参数写在路径上,不是带?的那种
public String selectOne(@PathVariable Integer id){
System.out.println("查询id为"+id+"的数据");
return "one";
}
//修改
@RequestMapping(value = "users/{id}",method = RequestMethod.PUT)
@ResponseBody
public String updata(@PathVariable Integer id){
System.out.println("修改id"+id+"的数据");
return "updata";
}
//保存新增
@RequestMapping(value = "users",method = RequestMethod.POST)
@ResponseBody
public String sava(){
System.out.println("新增保存");
return "save";
}
//删除
@RequestMapping(value = "users/{id}",method = RequestMethod.DELETE)
@ResponseBody
public String delelet(@PathVariable Integer id){
System.out.println("删除id为"+id);
return "delete";
}
}
使用@PathVariable注明路径参数,形参名要与 @RequestMapping路径上写的一致