Maven下载
https://wws.lanzous.com/icFBQhgbukj
Spring
<bean id="userdao" class="com.sdut.dao.UserDaoImpl" scope="prototype"/>
prototype 创建的对象不是同一个
singleton 创建的对象是同一个
Bean的依赖注入概念
依赖注入:它是Spring框架核心IOC的具体实现
在编写程序时,通过控制翻转,把对象的创建交给Spring,但是代码中不可能出现没有依赖的IOC解耦只是降低他们的依赖关系,但不会消除。例如:业务层仍然会调用持久层的方法,那这种业务层和持久层的依赖关系,在使用Spring之后,就让Spring来维护了。简单的说,就是坐等框架把持久层对象传入业务层,而不用我们去取。
service 中需要dao ,因此将dao注入到service
set方法注入
//UserDao.java
package com.sdut.dao;
public interface UserDao {
void save();
}
//UserDaoImpl.java
package com.sdut.dao;
public class UserDaoImpl implements UserDao{
@Override
public void save() {
System.out.println("Hello, Spring !");
}
}
//ServiceDemo.java
package com.sdut.service;
public interface ServiceDemo {
void save();
}
//ServiceDemoImpl.java
package com.sdut.service;
import com.sdut.dao.UserDao;
public class ServiceDemoImpl implements ServiceDemo{
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
@Override
public void save() {
userDao.save();
}
}
//applicationContext.xml
<bean id="userDao" class="com.sdut.dao.UserDaoImpl" />
<bean class="com.sdut.service.ServiceDemoImpl" id="serviceDemo">
<property name="userDao" ref="userDao"/> //name = "userDao" 是setter属性名去掉set第一个首字母变小写
</bean>
//通过p命名空间简化方法
<beans>
xmlns:p="http://www.springframework.org/schema/p"
<bean id="userDao" class="com.sdut.dao.UserDaoImpl" />
<bean id="serviceDemo" class="com.sdut.service.ServiceDemoImpl" p:userDao-ref="userDao"/>
</beans>
构造方法注入
其它与上面相同
//ServiceDemoImpl.java
package com.sdut.service;
import com.sdut.dao.UserDao;
public class ServiceDemoImpl implements ServiceDemo{
private UserDao userDao;
public ServiceDemoImpl(UserDao userDao) {
this.userDao = userDao;
}
@Override
public void save() {
userDao.save();
}
}
//applicationContext.xml
<bean id="userDao1" class="com.sdut.dao.UserDaoImpl" />
<bean id="serviceDemo" class="com.sdut.service.ServiceDemoImpl">
<constructor-arg name ="userDao" ref="userDao1"></constructor-arg>
</bean>
普通数据类型注入
//ServiceDemoImpl.java
package com.sdut.service;
import com.sdut.dao.UserDao;
public class ServiceDemoImpl implements ServiceDemo{
private String username;
private int age;
public void setUsername(String username) {
this.username = username;
}
public void setAge(int age) {
this.age = age;
}
@Override
public void save() {
System.out.println("姓名:"+username+", 年龄:"+age);
}
}
//applicationContext.xml
<bean id="serviceDemo" class="com.sdut.service.ServiceDemoImpl">
<property name="username" value="张三"/>
<property name="age" value="14"/>
</bean>
集合的注入
//ServiceDemoImpl.java
package com.sdut.service;
import com.sdut.daomain.User;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
public class ServiceDemoImpl implements ServiceDemo{
private List<String> lis;
private Map<String, User> map;
private Properties properties;
public void setLis(List<String> lis) {
this.lis = lis;
}
public void setMap(Map<String, User> map) {
this.map = map;
}
public void setProperties(Properties properties) {
this.properties = properties;
}
@Override
public void save() {
System.out.println(lis);
System.out.println(properties);
Set<String> sets = map.keySet();
for(String set: sets){
System.out.println(set+" : "+map.get(set).getName()+map.get(set).getAge());
}
}
}
//applicationContext.xml
<bean id="user1" class="com.sdut.daomain.User">
<property name="name" value="张三"/>
<property name="age" value="15"/>
</bean>
<bean id="user2" class="com.sdut.daomain.User">
<property name="name" value="李四"/>
<property name="age" value="16"/>
</bean>
<bean id="serviceDemo" class="com.sdut.service.ServiceDemoImpl">
<!-- 注入数组-->
<property name="lis">
<array>
<value>aaa</value>
<value>bbb</value>
<value>ccc</value>
<value>ddd</value>
</array>
</property>
<!-- 注入map-->
<property name="map">
<map>
<entry key="name1" value-ref="user1"/>
<entry key="name2" value-ref="user2"/>
</map>
</property>
<!-- 注入配置文件-->
<property name="properties">
<props>
<prop key="name">张三</prop>
<prop key="age">14</prop>
<prop key="address">北京</prop>
</props>
</property>
</bean>
Spring 注解开发
AOP 相关术语
- Target(目标对象):代理的目标对象
- Proxy(代理):一个类被AOP织入增强后,就产生一个结果代理类
- JoinPoint(连接点):被拦截到的点(公民)
- Pointcut(切入点):确定被增强的方法(人大代表)
- Advice:(通知):用于增强的方法
- Aspect(切面):切入点和通知的结合
- Weaving(织入):把增强应用到目标的过程
AOP开发通知类型
通知的语法
<aop:通知类型 method="切面类中的方法名" pointcut="切点表达式"></aop:切点表达式>
AOP实现
//TargetInter.java 目标对象接口,在进行测试依赖注入时只能通过接口接收target对象不明白(明白了,因为 动态代理代理的是接口所以只能通过接口接收,不能通过实现类接收,如果通过实现类接收就会出现错误)
package com.sdut.service;
public interface TargetInter {
void print();
}
//Target.java 目标对象,被增强对象
package com.sdut.service;
public class Target implements TargetInter{
@Override
public void print(){
System.out.println("I am target!");
}
}
//MyAspect.java 切面类用于增强
package com.sdut.service;
public class MyAspect {
public void before(){
System.out.println("I am before!");
}
public void aferReturning(){
System.out.println("I am afterReturning!");
}
}
//SpringJunitTest.java 测试类
package com.sdut;
import com.sdut.service.TargetInter;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
//@ContextConfiguration(classes = {SpringConfiguration.class})
@ContextConfiguration("classpath:applicationContext.xml")
public class SpringJunitTest {
@Autowired
private TargetInter target;
@Test
public void text2(){
target.print();
}
}
<!--applicationContext.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: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/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--目标对象-->
<bean id="target" class="com.sdut.service.Target"/>
<!--切面对象-->
<bean id="myaspect" class="com.sdut.service.MyAspect"/>
<!--配置织入告诉Spring哪些方法(切点)需要增强-->
<aop:config>
<!--声明切面-->
<aop:aspect ref="myaspect">
<!--声明通知的种类是before前置通知,声明通知方法before,声明切点(要被增强的方法)-->
<aop:before method="before" pointcut="execution(* com.sdut.service.Target.print())"/>
</aop:aspect>
</aop:config>
</beans>
切点表达式的抽取
<aop:config>
<!--将切点表达式进行抽取-->
<aop:pointcut id="point1" expression="execution(* com.sdut.service.Target.print())"/>
<!--声明切面-->
<aop:aspect ref="myaspect">
<!--声明通知的种类是before前置通知,声明通知方法before,声明切点(要被增强的方法)-->
<aop:before method="before" pointcut-ref="point1"/>
</aop:aspect>
</aop:config>
通过注解实现AOP
//TargetInter.java 同上
//Target.java 目标对象,被增强对象
package com.sdut.service;
import org.springframework.stereotype.Component;
@Component("target")
public class Target implements TargetInter{
@Override
public void print(){
System.out.println("I am target!");
}
}
//MyAspect.java 切面类用于增强
package com.sdut.service;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
@Component("myaspect")
@Aspect
public class MyAspect {
@Before("execution(* com.sdut.service.Target.print())")
public void before(){
System.out.println("I am before!");
}
public void aferReturning(){
System.out.println("I am afterReturning!");
}
}
//SpringJunitTest.java 测试类 同上
<!--applicationContext.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: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 http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<context:component-scan base-package="com.sdut"/>
<aop:aspectj-autoproxy/>
</beans>
Spring中事务的管理
Java异常继承体系
@Transactional失效场景
- @Transactional 应用在非 public 修饰的方法上
- Spring默认抛出了未检查unchecked异常(继承自 RuntimeException 的异常)或者 Error才回滚事务;其他异常不会触发回滚事务。
- 异常被catch捕获
- 开发中避免不了会对同一个类里面的方法调用,比如有一个类Test,它的一个方法A,A再调用本类的方法B(不论方法B是用public还是private修饰),但方法A没有声明注解事务,而B方法有。则外部调用方法A之后,方法B的事务是不会起作用的。
是由于使用Spring AOP代理造成的,因为只有当事务方法被当前类以外的代码调用时,才会由Spring生成的代理对象来管理。
注解方式实现切点表达式的抽取
在切面类中定义一个空实现的方法
Pointcut("execution(* com.sdut.service.Target.print())")
public void pointcut(){}
@Before("类名.pointcut()")
public void before(){}
全注解实现AOP
//DruidConfiguration.java 连接数据库相关配置类
package com.sdut.config;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.jdbc.core.JdbcTemplate;
import javax.sql.DataSource;
import java.io.FileReader;
import java.util.Properties;
public class DruidConfiguration {
@Bean("dataSource")
public DataSource getDataSource(){
DataSource dataSource = null;
Properties properties = new Properties();
String file = DruidConfiguration.class.getClassLoader().getResource("druid.properties").getPath();
try {
properties.load(new FileReader(file));
dataSource = DruidDataSourceFactory.createDataSource(properties);
} catch (Exception e) {
e.printStackTrace();
}
assert dataSource != null;
return dataSource;
}
@Bean("jdbcTemplate")
public JdbcTemplate getJdbcTemplate(DataSource dataSource){
return new JdbcTemplate(dataSource);
}
}
//SpringConfiguration.java 主配置类
package com.sdut.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@Configuration
@ComponentScan("com.sdut")
@Import({DruidConfiguration.class,TransactionConfiguration.class})
@EnableTransactionManagement
public class SpringConfiguration {
}
//TransactionConfiguration.java 与事务相关的配置类
package com.sdut.config;
import org.springframework.context.annotation.Bean;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import javax.sql.DataSource;
public class TransactionConfiguration {
@Bean("transactionManager")//配置事务注解驱动
public PlatformTransactionManager createTransactionManager(DataSource dataSource){
return new DataSourceTransactionManager(dataSource);
}
}
//Transfer.java 转账操作接口
package com.sdut.dao.impl;
public interface Transfer {
void in(double number, int id);
void out(double number, int id);
}
//TransferImpl.java 实现转账操作
package com.sdut.dao;
import com.sdut.dao.impl.Transfer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
@Component("transferImpl")
public class TransferImpl implements Transfer {
@Autowired
private JdbcTemplate jdbctemplate ;
@Override
public void in(double number,int id) {
String sql = "update account set money=money+? where id = ?";
jdbctemplate.update(sql,number,id);
}
@Override
public void out(double number,int id) {
String sql = "update account set money=money-? where id = ?";
jdbctemplate.update(sql,number,id);
}
}
//TrasferService.java 转账服务接口
package com.sdut.serivice.impl;
public interface TrasferService {
void tansfer(int outid, int inid, double number);
}
//TrasferServiceImpl.java 实现转账服务
package com.sdut.serivice;
import com.sdut.dao.TransferImpl;
import com.sdut.serivice.impl.TrasferService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
@Component("trasferServiceImpl")
public class TrasferServiceImpl implements TrasferService {
@Autowired
private TransferImpl transferImpl;
@Override
@Transactional
public void tansfer(int outid, int inid, double number) {
transferImpl.out(number,outid);
//int i = 9/0;
transferImpl.in(number,inid);
}
}
//SpringJunitTest.java 测试类
package sdut;
import com.sdut.config.SpringConfiguration;
import com.sdut.serivice.impl.TrasferService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {SpringConfiguration.class})
public class SpringJunitTest {
@Autowired
private TrasferService trasferServiceImpl;
@Test
public void test() {
trasferServiceImpl.tansfer(1001,1002,500);
}
}
SpringMVC
入门级SpringMVC程序
https://wws.lanzous.com/iW21phoewda
@RequestMapping注解
参数:
- value,path: 请求路径
- method: 请求方式,参数是枚举类,多个用{RequestMethod.get}
- params:用于指定限制请求参数的条件,它支持简单的表达式,要求请求参数key和value必须和配置的一模一样。例如 params = {"name"} 请求参数必须有name ;params = {"name = haha"} 请求参数必须有name 并且值必须为haha
- headers 限制请求必须包含请求头例如 headers = {"accept"}
请求参数绑定
//客户端界面想把username和password两个参数传进去
<a href="hello?username=root&password=123">进入SpringMVC入门程序</a>
@RequestMapping("/hello") //在方法上传入与key相同的参数
public String print(String username, String password){
System.out.println("Hello! SpringMVC");
return "success";
}
请求参数绑定实体类型
//User.java
package edu.sdut.domain;
public class User implements Serializable {
private String name;
private Integer age;
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
//Account.java
package edu.sdut.domain;
import java.io.Serializable;
public class Account implements Serializable {
private String username;
private String password;
private Double money;
private User user;
@Override
public String toString() {
return "Account{" +
"username='" + username + '\'' +
", password='" + password + '\'' +
", money=" + money +
", user=" + user +
'}';
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Double getMoney() {
return money;
}
public void setMoney(Double money) {
this.money = money;
}
}
//SaveController.java
package edu.sdut.controller;
import edu.sdut.domain.Account;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class SaveController {
@RequestMapping("/save") //请求参数绑定把数据封装到Javabean的实体类中
public String save(Account account){
System.out.println(account);
return "success";
}
}
//index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Spring</title>
<style>
body{
text-align: center;
}
</style>
</head>
<body>
<form action="save">
用户名:<input type="text" name="username"/> <br>
密码:<input type="password" name="password"/> <br>
金额:<input type="text" name="money"/><br>
姓名:<input type="text" name="user.name"/><br>
年龄:<input type="text" name="user.age"/><br>
<input type="submit" value="提交">
</form>
</body>
</html>
解决客户端提交数据中文乱码问题
web.xml
<!--配置过滤器解决中文乱码问题-->
<filter>
<filter-name>characterEncodingFilter</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>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
自定义类型转换器
HTML表单提交的都是String类型的数据,但是我们可以直接对提交的数据进行封装,而不用考虑类型,这是一位Spring内部帮我们进行了类型转换,例如2020/10/23,其对应的属性如果是Date类型的话就会被转换成Date类型数据,但是2020-10-23这样就没有办法进行转换,这时我们如果想让其转换可以自定义类型转换器
//StringToDate.java 自定义类型转换类继承Conver接口,重写convert方法
package edu.sdut.util;
import org.springframework.core.convert.converter.Converter;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class StringToDate implements Converter<String, Date> {
@Override
public Date convert(String s) {
DateFormat dataFormat = new SimpleDateFormat("yyyy-MM-dd");
try {
return dataFormat.parse(s);
} catch (ParseException e) {
throw new RuntimeException("数据类型转换异常");
}
}
}
//springmvc.xml
<!--配置自定义类型转换器-->
<bean id="conversionServiceFactoryBean" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="edu.sdut.util.StringToDate"/>
</set>
</property>
</bean>
<!--开启SpringMVC框架的注解的支持,使自定义类型转换器生效-->
<mvc:annotation-driven conversion-service="conversionServiceFactoryBean"/>
Mybatis
编写sql 语句是用传入参数#{}和${}的区别是,#{}是预编译的相当于PrepareStatement,可以防止sql注入
lombok插件,通过注解生成getter,setter,构造方法和toString方法
按照查询嵌套处理多对一
<mapper namespace="edu.sdut.dao.StudentDao">
<select id="findStudent" resultMap="studentTeacher">select * from student</select>
<resultMap id="studentTeacher" type="edu.sdut.domain.Student">
<!--teacher是javaBean类中的teacher字端,使其与查到的tid对应起来-->
<association property="teacher" column="tid" javaType="edu.sdut.domain.Teacher" select="findTeacher"/>
</resultMap>
<select id="findTeacher" resultType="edu.sdut.domain.Teacher">select * from teacher</select>
</mapper>
按照结果处理多对一
<select id="findStudent2" resultMap="studentTeacher2">select s.id sid,s.`name` sname,t.`name` tname from teacher t,student s where t.id = s.tid;</select>
<resultMap id="studentTeacher2" type="edu.sdut.domain.Student">
<result property="id" column="sid"/>
<result property="name" column="sname"/>
<association property="teacher" javaType="edu.sdut.domain.Teacher">
<result property="name" column="tname"/>
</association>
</resultMap>
按照查询嵌套处理一对多
<!--按照查询嵌套处理-->
<select id="findTeacher2" resultMap="teacherStudent2">select * from teacher where id = 1</select>
<select id="findStudent" resultType="edu.sdut.domain.Student">select * from student where tid = #{id}</select>
<resultMap id="teacherStudent2" type="edu.sdut.domain.Teacher">
<collection property="students" javaType="java.util.ArrayList" ofType="edu.sdut.domain.Student" select="findStudent" column="id"/>
</resultMap>
按照结果处理一对多
<!--处理查询结果查询-->
<select id="findTeacher" resultMap="teacherStudent">select t.id tid, t.`name` tname, s.id sid, s.`name` sname from student s,teacher t WHERE t.id = s.tid and t.id = 1 </select>
<resultMap id="teacherStudent" type="edu.sdut.domain.Teacher">
<result property="id" column="tid"/>
<result property="name" column="tname"/>
<collection property="students" ofType="edu.sdut.domain.Student">
<result property="id" column="sid"/>
<result property="name" column="sname"/>
</collection>
</resultMap>
小结
log4j日志工厂的使用
//导入相关jar包
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
//配置文件中配置
<!--配置日志工厂-->
<settings>
<!--标准日志工厂-->
<!--<setting name="logImpl" value="STDOUT_LOGGING"/>-->
<setting name="logImpl" value="LOG4J"/>
</settings>
//配置文件设置 log4j.properties
#将等级为DEBUG的日志信息输出到console和file这两个目的地,console和file的定义在下面的代码
log4j.rootLogger=DEBUG,console,file
#控制台输出的相关设置
log4j.appender.console = org.apache.log4j.ConsoleAppender
log4j.appender.console.Target = System.out
log4j.appender.console.Threshold=DEBUG
log4j.appender.console.layout = org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=[%c]-%m%n
#文件输出的相关设置
log4j.appender.file = org.apache.log4j.RollingFileAppender
log4j.appender.file.File=./log/run.log
log4j.appender.file.MaxFileSize=10mb
log4j.appender.file.Threshold=DEBUG
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=[%p][%d{yy-MM-dd}][%c]%m%n
#日志输出级别
log4j.logger.org.mybatis=DEBUG
log4j.logger.java.sql=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.ResultSet=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG
//简单使用
package edu.sdut.dao;
import org.apache.log4j.Logger;
import org.junit.Test;
public class LogTest {
@Test
public void test(){
Logger logger = Logger.getLogger(LogTest.class);
logger.info("info:running");
logger.debug("debug:running");
logger.error("error:running");
}
}
缓存
一级缓存是默认开启的只在一次sqlSession 中有效,也就是从拿到sqlSession 到关闭之间有效