1.环境搭建
1.1创建maven项目
pom文件导入项目依赖jar包
<dependencies>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.6</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.19</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
lombok是用来在当中引入注解,不用手动创建类中的构造函数和getter、setter方法
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
</dependency>
</dependencies>
1.2完成环境配置文件mybatis-config.xml
引入xml约束
<?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">
基本功能实现的配置文件
<?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">
<!--config 约束-->
<configuration>
<!--引入外部配置文件-->
<!--将连接数据库的信息写在db.properties中-->
<properties resource="db.properties"/>
<!--日志工厂 #日志工厂
#如果一个数据库操作出现异常,日志就是最好的助手
-->
<settings>
<!--标准日志工厂实现-->
<setting name="logImpl" value="STDOUT_LOGGING"/>
<!--<setting name="logImpl" value="log4j"/>-->
</settings>
<!-- typeAlias类型别名,为java类中设置一个别名-->
<typeAliases>
<!--方法①,可以自定义随便定义名字-->
<!--<typeAlias type="entity.User" alias="User"/>-->
<!--方法②可以指定一个包名,mybatis会自动在这个包名下搜索所需要的javaBean,比如扫描实体类的包,默认别名就是为这个类的类名。首字母小写可以给实体类起别名-->
<package name="entity"/>
<!--方法③使用注解@Alias("xxx")在类的名字上面加-->
</typeAliases>
<!--配置环境-->
<environments default="mysql">
<!--配置mysql环境-->
<environment id="mysql">
<!--配置事务的类型-->
<transactionManager type="JDBC"></transactionManager>
<!--配置数据源(连接池)-->
<dataSource type="POOLED">
<!--皆从db.properties文件中获取数据库连接信息-->
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<!--指定映射配置文件的位置,映射文件指的是每个dao独立的配置文件-->
<!--MapperRegistry:注册绑定Mapper文件-->
<mappers>
<mapper resource="mapper/UserMapper.xml"/>
<mapper resource="mapper/TeacherMapper.xml"/>
<mapper resource="mapper/StudentMapper.xml"/>
</mappers>
</configuration>
1.3创建db.propertis文件
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis_self?serverTimezone=UTC
username=root
password=2580
1.4创建MybatisUtils
public class MybatisUtils {
private static SqlSessionFactory sqlSessionFactory;
static{
try {
String resourse="mybatis-config.xml";
InputStream inputStream= Resources.getResourceAsStream(resourse);
//SqlSessionFactoryBuilder只实例化一次,一旦创建SqlSessionFactory就没用了
/*
sqlSessionFactory一旦创建就一直存在,没有任何理由去创建另一个实例
最佳作用域是应用作用域,创建多浪费资源,最简单就是单例模式或者静态单例模式
*/
sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
/*
sqlSession
增删改查皆使用sqlSession,不再使用jdbc中的Statement或者PreparedStatement
使用完立即关闭,否则浪费资源
实例现成不安全,不能共享
每收到一个http请求都会创建一个sqlsession
*/
public static SqlSession getSqlSession(){
//如果sqlSessionFactory.openSession()方法中传入一个true,即代表对数据库进行操作
//是自动提交,如果没有传入,在操作时候需要手动提交sqlsession的commit()方法,才能完成对数 据库的操作(例如更新,插入操作)
return sqlSessionFactory.openSession();
}
}
#<!--
##什么是log4j 可以控制日志信息输送的目的地是控制台,文件,GUI组件
##可以控制每一条日志的输出格式
##定义每一条日志信息的级别,能更加细致控制日志的生成过程
##通过一个配置文件来灵活进行配置,不需要修改应用代码
##-->
log4j.rootLogger=debug, stdout, R
#控制台输出相关配置
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p - %m%n
#文件输出相关配置
log4j.appender.R=org.apache.log4j.RollingFileAppender
log4j.appender.R.File=firestorm.log
log4j.appender.R.MaxFileSize=100KB
log4j.appender.R.MaxBackupIndex=1
log4j.appender.R.layout=org.apache.log4j.PatternLayout
log4j.appender.R.layout.ConversionPattern=%p %t %c - %m%n
#日志输出类别
log4j.logger.com.codefutures=DEBUG
## 4.创建mapper文件
resource目录下创建mapper包
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8e6e7Opd-1609410796699)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201126162529648.png)]
dao包下面存放pojo借口类,定义方法,无需实现。
案例:
```java
public interface IUserDao {
List<User>findAll();
User getUserById(int id);
int insertUser(User user);
int updateUser(User user);
int deleteUserById(User user);
// 使用mybatis完成分页功能
List<User>getUserByLimit(Map<String, Integer> map);
}
UserMapper.xml
注:
resultType 返回的是一个结果
resultMap返回的是一个集合
parameterType参数类型
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--命名空间绑定的是pojo的接口类-->
<mapper namespace="dao.IUserDao">
<!--resultMap功能是结果集映射,解决字段名和数据库表中属性名不一致的问题-->
<!--如果resultMap中的字段和数据库中的属性名一致,可以不用写-->
<resultMap id="userMap" type="User">
<result column="id" property="id"/>
<result column="username" property="username"/>
<result column="sex" property="sex"/>
<result column="address" property="add"/>
</resultMap>
<select id="findAll" resultMap="userMap">
select * from user
</select>
<!--resultType是返回值类型-->
<!--<select id="findAll" resultType="User">-->
<!--select * from user;-->
<!--</select>-->
<!--parameterType是参数类型-->
<select id="getUserById" parameterType="int" resultType="entity.User">
select * from user where id=#{id}
</select>
<insert id="insertUser" parameterType="entity.User" >
insert into user(username,birthday,sex,address) values(#{username},#{birthday},#{sex},#{address});
</insert>
<update id="updateUser" parameterType="entity.User">
update user set username=#{username} where id=#{id}
</update>
<delete id="deleteUserById" parameterType="int">
delete from user where id=#{id}
</delete>
<!--分页-->
<select id="getUserByLimit" parameterType="map" resultMap="userMap">
select * from user limit #{startIndex},#{pageSize}
</select>
5.1引入lombokjar包
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zrmud09e-1609410796700)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201126163525823.png)]
5.2注解实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
//Data注解:无参构造、get、set、tostring、hashcode、equals
//@AllArgsConstructor 生成有参构造
//@NoArgsConstructor 生成无参构造
public class User implements Serializable {
private Integer id;
private String username;
private String sex;
private String add;
}
动态sql的几大标签
1.If
<select id="queryBlog" parameterType="map" resultType="blog">
SELECT * FROM blog
<where>
<if test="title != null">
title=#{title}
</if>
<if test="views != null">
and views =#{views}
</if>
</where>
</select>
2.trim(where,set)
where元素只会在查询语句中至少满足一个条件下才会插入where语句,且语句中如果有and或者or开头的,where也会将其去掉
<select id="queryBlog" parameterType="map" resultType="blog">
SELECT * FROM blog
<where>
<if test="title != null">
title=#{title}
</if>
<if test="views != null">
and views =#{views}
</if>
</where>
</select>
案例1:
Test类中没有对于map没有传递任何数据值,
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7ZEX4tW3-1609410796702)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201126144940304.png)]
Mapper文件SQL语句
<select id="queryBlog" parameterType="map" resultType="blog">
SELECT * FROM blog
<where>
<if test="title != null">
title=#{title}
</if>
<if test="views != null">
and views =#{views}
</if>
</where>
</select>
运行结果
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IBnMLTEA-1609410796705)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201126144905126.png)]
test类中赋值
public class TeacherTest {
@Test
public void test(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
IBlogDao mapper = sqlSession.getMapper(IBlogDao.class);
HashMap map=new HashMap();
map.put("title","spring全家桶");
// map.put("author","胡雅楠");
map.put("views",5555);
List<Blog> blogs = mapper.queryBlog(map);
for (Blog blog : blogs) {
System.out.println(blog);
}
sqlSession.close();
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wDA0T6lc-1609410796706)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201126145525478.png)]
public class TeacherTest {
@Test
public void test(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
IBlogDao mapper = sqlSession.getMapper(IBlogDao.class);
HashMap map=new HashMap();
map.put("title","spring全家桶");
// map.put("author","胡雅楠");
// map.put("views",5555);
List<Blog> blogs = mapper.queryBlog(map);
for (Blog blog : blogs) {
System.out.println(blog);
}
sqlSession.close();
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FgntPnCS-1609410796709)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201126145704951.png)]
3.choose(when,otherwise)
choose相当于java中的switch case 语句
<select id="queryBlogChoose" parameterType="map" resultType="Blog">
select * from blog
<where>
<choose>
<when test="title != null">
title=#{title}
</when>
<when test="author != null">
and author=#{author}
</when>
<otherwise>
and views=#{views}
</otherwise>
</choose>
</where>
</select>
SQL片段:
有时候将一些公共部分抽取出来方便复用。
1.在使用sql标签抽取公共部分
<sql id="dynamicSqlRepeatCodeIntgrate">
<if test="title != null">
title=#{title}
</if>
<if test="views != null">
and views =#{views}
</if>
</sql>
2.在需要使用的地方使用include标签引用即可
<select id="queryBlogSql" parameterType="map" resultType="blog">
SELECT * FROM blog
<where>
<include refid="dynamicSqlRepeatCodeIntgrate"></include>
</where>
</select>
注意事项:
最好基于单表定义sql片段
不要在1中存在where标签
注意:open中的and和括号必须有空格,否则报错
<!--foreach标签使用 select * from blog where 1=1 and(id=1 or id=2 or id=3) -->
<select id="selectByForeach" parameterType="map" resultType="blog" >
select * from blog
<where>
<foreach collection="ids" item="id" open="and(" close=")" separator="or">
id=#{id}
</foreach>
</where>
</select>
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-q3ndhm6F-1609410796711)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201130155031912.png)]
正确写法:
<select id="selectByForeach" parameterType="map" resultType="blog" >
select * from blog
<where>
<foreach collection="ids" item="id" open="and (" close=")" separator="or">
id=#{id}
</foreach>
</where>
</select>
@Test
public void testSelectByForeach(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
IBlogDao mapper = sqlSession.getMapper(IBlogDao.class);
HashMap map=new HashMap();
List<String> ids=new ArrayList<String>();
ids.add("1");
ids.add("2");
ids.add("3");
map.put("ids",ids);
List<Blog> blogs = mapper.selectByForeach(map);
for (Blog blog : blogs) {
System.out.println(blog);
}
sqlSession.close();
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aNbLaHMW-1609410796712)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201130155208459.png)]
如果ids是为空的没有赋值的集合,mybatis会自动忽略后面的标签,实际语句变成select * from blog
@Test
public void testSelectByForeach(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
IBlogDao mapper = sqlSession.getMapper(IBlogDao.class);
HashMap map=new HashMap();
List<String> ids=new ArrayList<String>();
map.put("ids",ids);
List<Blog> blogs = mapper.selectByForeach(map);
for (Blog blog : blogs) {
System.out.println(blog);
}
sqlSession.close();
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Di26H5eZ-1609410796715)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201130155406570.png)]
动态sql就是在拼接sql语句,只要保证sql的正确性,按照sql格式,排列组合即可
13.1.简介
1.什么是缓存?
2.为什么使用缓存?
3,什么样的数据使用缓存?
13.2.一级缓存
一级缓存也叫本地缓存 Sqlsession
与数据库同一次会话期间查询到的数据会放在本地缓存中
以后如果需要获取相同的数据,直接从缓存中拿,没必须再去查询数据库
//查询只走了一次
public class UserTest {
@Test
public void testUserCache(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
IUserDao mapper = sqlSession.getMapper(IUserDao.class);
User user = mapper.getUserById(3);
System.out.println(user);
System.out.println("=============");
User user1 = mapper.getUserById(3);
System.out.println((user==user1));
sqlSession.close();
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UJLQZjPj-1609410796717)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201130163324332.png)]
缓存失效情况:
1.查询不同的东西
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-q5837sVn-1609410796718)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201130163940453.png)]
2.增删改操作,可能会改变原来的数据,所以必定会刷新缓存
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-buljtwnd-1609410796720)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201130183529671.png)]
3.查询不同的mapper.xml
4.手动清理缓存
sqlsession.clearCache();
小结:一级缓存默认是开启的,只在一次sqlsession中有效,也就是拿到连接关闭这个连接的区间之间。一级缓存相当于一个Map
13.3.二级缓存
在mapper.xml文件中加入一个就是二级缓存
映射语句中所有select语句会被缓存
映射语句文件中所有insert,update,delete语句会刷新缓存
缓存会使用最近最少使用算法(LRU,)
# Spring学习
spring优点:
1.一个开源免费框架
2.一个轻量级,非入侵式框架
3.控制反转IOC,面向切面编程AOP
4.支持事务处理,对框架整合的支持
总结:spring是一个轻量级的控制反转IOC和面向切面编程的框架
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OtlreqGs-1609411012065)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201127113250819.png)]
Spring Boot
一个快速的开发脚手架
基于SpringBoot可以快速开发的单个微服务
约定大于配置
SpringCloud
SpringCloud是基于SpringBoot实现的
弊端:发展太久,违背原来理念,配置十分繁琐,所以要学习springboot
1、UserDao 接口
2、UserDaoImpl实现类
3、UserService业务接口
4、UserServiceImpl业务实现类
理解:
dao包下面放置了多个业务,用户想使用不同的业务时候,程序员要在UserServiceImpl中实例化不同的对象,要程序员根据用户需求修改代码。[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dz5rfeGT-1609411012067)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201202125622550.png)]
public class UserServiceImpl implements UserService {
//用户实际调用的是业务层,dao层不需要他们接触
private UserDao userDao=new UserDaoOracleImpl();
//每次用户提出不同的要求,程序员都要在UserServiceImpl修改代码,控制权在程序员手上,如果项目庞大,改动十分繁琐
public void getUser() {
userDao.getUser();
}
}
修改UserServiceImpl中的代码
public class UserServiceImpl implements UserService {
//通过setter注入,在将控制权翻转,控制权不在程序员手上,而是在用户手上。
//使用setter注入,程序不再具有主动性,而是被动变成了接收对象,这就是控制反转思想
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public void getUser() {
userDao.getUser();
}
}
耦合性大大降低,可以更专注业务的实现,这是IOC的原型,思想
导包:spring-webmvc spring-jdbc
创建目录如下
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vhlyRKDw-1609411012071)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201202150004152.png)]
在resource目录下创建applicationContext.xml文件
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="hello" class="com.huang.pojo.Hello">
<property name="str" value="spring"/>
bean>
<bean id="UserDaoImpl" class="com.huang.dao.UserDaoImpl"/>
<bean id="UserDaoMysqlImpl" class="com.huang.dao.UserDaoMysqlImpl"/>
<bean id="UserServiceImpl" class="com.huang.service.UserServiceImpl">
<property name="userDao" ref="UserDaoImpl">property>
bean>
beans>
测试类:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UGHLbrdG-1609411012074)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201202150536493.png)]
思考问题:
对象是谁创建的?
对象的属性是怎么设置的?
这个过程就叫控制反转:
控制:谁来控制对象的创建,传统应用程序的对象是由程序本身控制创建的,使用Spring之后,对象是由Spring来创建的。
反转:程序本事不创建对象,而变成被动的接收对象。
依赖注入:就是利用set方法来进行注入。
IOC是一种编程思想,由主动编程变成被动的接收
1.使用无参构造创建对象(系统默认方式)
2.有参构造
1.下标赋值。实体类中写有参构造
public class User {
private String username;
public User(String username) {
this.username = username;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
@Override
public String toString() {
return "User{" +
"username='" + username + '\'' +
'}';
}
}
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="hello" class="com.huang.pojo.Hello">
<property name="str" value="spring"/>
bean>
beans>
2.通过类型创建,不建议使用
<bean id="user" class="com.huang.pojo.User">
<constructor-arg type="java.lang.String" value="huang"/>
bean>
3.直接通过参数名来设置
<bean id="user" class="com.huang.pojo.User">
<constructor-arg name="username" value="huang"/>
bean>
总结:配置文件加载时候,容器中管理的对象已经被初始化了
alias另起别名,类似mybatis中的起别名
<bean id="user" class="com.huang.pojo.User">
<constructor-arg name="username" value="huang"/>
bean>
<alias name="user" alias="userNew"/>
public class SpringTest {
public static void main(String[] args) {
ApplicationContext context=new ClassPathXmlApplicationContext("ApplicationContext.xml");
User user=(User) context.getBean("userNew");
System.out.println(user.toString());
}
}
id:bean的唯一标识符,相当于对象名
name:也是别名,name可以同时取多个别名
class:bean对象所对应的全限定名:包名+类型
scope:
<bean id="user" class="com.huang.pojo.User" name="user1 user2">
<constructor-arg name="username" value="huang"/>
bean>
一般用于团队开发使用,可以将多个配置文件,汇总成一个.
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cgMRhB2g-1609411012080)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201203134840508.png)]
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<import resource="applicationcontext.xml"/>
beans>
前面已经说过了
依赖注入:set注入
依赖:bean对象创建依赖于容器
注入:bean对象中的所有属性,由容器来注入
实体类
public class Address {
private String address;
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString() {
return "Address{" +
"address='" + address + '\'' +
'}';
}
}
public class Student {
private String name;
private Address address;
private String[] books;
private List<String> hobbys;
private Map<String,String> card;
private Set<String> games;
private String wife;
private Properties info;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
public String[] getBooks() {
return books;
}
public void setBooks(String[] books) {
this.books = books;
}
public List<String> getHobbys() {
return hobbys;
}
public void setHobbys(List<String> hobbys) {
this.hobbys = hobbys;
}
public Map<String, String> getCard() {
return card;
}
public void setCard(Map<String, String> card) {
this.card = card;
}
public Set<String> getGames() {
return games;
}
public void setGames(Set<String> games) {
this.games = games;
}
public String getWife() {
return wife;
}
public void setWife(String wife) {
this.wife = wife;
}
public Properties getInfo() {
return info;
}
public void setInfo(Properties info) {
this.info = info;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", address=" + address.getAddress() +
", books=" + Arrays.toString(books) +
", hobbys=" + hobbys +
", card=" + card +
", games=" + games +
", wife='" + wife + '\'' +
", info=" + info +
'}';
}
}
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="address" class="com.huang.pojo.Address">
<property name="address" value="江苏省徐州市睢宁县官山镇黄圩村"/>
bean>
<bean id="student" class="com.huang.pojo.Student">
<property name="name" value="huangyuhang"/>
<property name="address" ref="address" />
<property name="books">
<array>
<value>javaEEvalue>
<value>c#value>
<value>pythonvalue>
array>
property>
<property name="hobbys">
<list>
<value>音乐value>
<value>篮球value>
list>
property>
<property name="card">
<map>
<entry key="身份证" value="320324199609094477"/>
map>
property>
<property name="games">
<set>
<value>LOLvalue>
<value>COCvalue>
set>
property>
<property name="wife">
<null/>
property>
<property name="info">
<props>
<prop key="学号">Z2019120114prop>
props>
property>
bean>
beans>
使用p命名空间和c命名空间来进行注入
P命名空间注入
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean name="john-classic" class="com.example.Person">
<property name="name" value="John Doe"/>
<property name="spouse" ref="jane"/>
bean>
<bean name="john-modern"
class="com.example.Person"
p:name="John Doe"
p:spouse-ref="jane"/>
<bean name="jane" class="com.example.Person">
<property name="name" value="Jane Doe"/>
bean>
beans>
只创建一个实例
<bean id="address" class="com.huang.pojo.Address" scope="singleton">
<property name="address" value="江苏省徐州市睢宁县官山镇黄圩村"/>
bean>
public static void main(String[] args) {
ApplicationContext context=new ClassPathXmlApplicationContext("applicationcontext.xml");
Student student=(Student) context.getBean("student");
Student student1=(Student)context.getBean("student");
System.out.println(student==student1);
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZeqwMfzA-1609411012081)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201203193436013.png)]
每次从容器get时候都会产生一个新的对象
<bean id="student" class="com.huang.pojo.Student" scope="prototype">
<property name="name" value="huangyuhang"/>
<property name="address" ref="address" />
bean>
public static void main(String[] args) {
ApplicationContext context=new ClassPathXmlApplicationContext("applicationcontext.xml");
Student student=(Student) context.getBean("student");
Student student1=(Student)context.getBean("student");
System.out.println(student==student1);
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ORPafMbj-1609411012083)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201203193350602.png)]
session
application
request
websocket
此四大对象只能在web开发中使用到
自动装配事sping满足bean依赖一种方式
spring会在上下文中自动寻找,并自动给bean装配属性
在spring中又三种装配方式
1.xml显示配置
<bean id="dog" class="com.huang.autowiredtest.pojo.Dog"/>
<bean id="cat" class="com.huang.autowiredtest.pojo.Cat"/>
<bean id="people" class="com.huang.autowiredtest.pojo.People">
<property name="cat" ref="cat"/>
<property name="dog" ref="dog"/>
<property name="name" value="huang"/>
bean>
实体类
public class Cat {
public void shout(){
System.out.println("miaomiao");
}
}
public class Dog {
public void shout(){
System.out.println("wangwang");
}
}
public class People {
private Dog dog;
private Cat cat;
private String name;
public Dog getDog() {
return dog;
}
public void setDog(Dog dog) {
this.dog = dog;
}
public Cat getCat() {
return cat;
}
public void setCat(Cat cat) {
this.cat = cat;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Test类
public class AutoWiredTest {
@Test
public void testAutoWired(){
ApplicationContext context=new ClassPathXmlApplicationContext("applicationcontext.xml");
People people = context.getBean("people", People.class);
people.getCat().shout();
people.getDog().shout();
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DST3qIgq-1609411012084)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201203200035236.png)]
2.java显示配置
3.隐式的自动装配Bean(重要)
第一种:
通过autowire=byName属性
<bean id="dog" class="com.huang.autowiredtest.pojo.Dog"/>
<bean id="cat" class="com.huang.autowiredtest.pojo.Cat"/>
<bean id="people" class="com.huang.autowiredtest.pojo.People" autowire="byName">
<property name="name" value="huang"/>
bean>
public class AutoWiredTest {
@Test
public void testAutoWired(){
ApplicationContext context=new ClassPathXmlApplicationContext("applicationcontext.xml");
People people = context.getBean("people", People.class);
people.getCat().shout();
people.getDog().shout();
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OwOmlOSG-1609411012086)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201203200219228.png)]
如果将cat名字改掉
<bean id="dog" class="com.huang.autowiredtest.pojo.Dog"/>
<bean id="cat111" class="com.huang.autowiredtest.pojo.Cat"/>
<bean id="people" class="com.huang.autowiredtest.pojo.People" autowire="byName">
<property name="name" value="huang"/>
bean>
public class AutoWiredTest {
@Test
public void testAutoWired(){
ApplicationContext context=new ClassPathXmlApplicationContext("applicationcontext.xml");
People people = context.getBean("people", People.class);
people.getCat().shout();
people.getDog().shout();
}
}
会导致空指针异常找不到cat
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jB6WbDLm-1609411012086)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201203200332235.png)]
如果将autowire=byType
<bean id="dog" class="com.huang.autowiredtest.pojo.Dog"/>
<bean id="cat111" class="com.huang.autowiredtest.pojo.Cat"/>
<bean id="people" class="com.huang.autowiredtest.pojo.People" autowire="byType">
<property name="name" value="huang"/>
bean>
public class AutoWiredTest {
@Test
public void testAutoWired(){
ApplicationContext context=new ClassPathXmlApplicationContext("applicationcontext.xml");
People people = context.getBean("people", People.class);
people.getCat().shout();
people.getDog().shout();
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OLrkCJVT-1609411012088)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201203200504576.png)]
总结:byName会自动在容器上下文中查找,和自己对象set方法后的值对应的beanId
byType会自动在容器上下文中查找,和自己对象属性类型相同的bean(要保证类型全局唯一,且byType可以将beanid省略,把cat的beanid和dog的beanid去掉)
byname:需要保证所有的baan的id唯一,且bean需要和自动注入属性的set方法的值一致
byType:需要保证所有bean的class唯一,且这个bean需要和自动注入的属性的类型一致
jdk1.5 spring2.5就支持了
使用注解须知:
1.导入配置约束 context约束
2.配置注解的支持
<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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
beans>
@AutoWired:直接在属性上放置即可,可以忽略set方法在实体类中
使用AutoWired我们可以不用编写set方法了,前提是你这个自动装配的属性在IOC(Spring)容器中存在,且符合名字Byname
科普:
@nullable:字段标记了这个注解,说明这个字段可以为null
@Autowired(required=false):显示定义了autowired属性为false,说明这个对象可以为null,否则不允许为空
@qualifier(value="xxx")可以在实体类中的属性名上自定义名字,然后与bean文件中的id名一致即可
如果@AutoWired自动装配环境比较复杂,自动装配无法通过一个注解[@Autowired]完成的时候,我们可以使用@qualifier(value=“xxx”)去配置@Autowired的使用,指定一个唯一的bean对象(Autowired与qualifier是一套)
<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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
<bean id="dog11" class="com.huang.autowiredtest.pojo.Dog"/>
<bean id="cat21" class="com.huang.autowiredtest.pojo.Cat"/>
<bean id="dog111" class="com.huang.autowiredtest.pojo.Dog"/>
<bean id="cat222" class="com.huang.autowiredtest.pojo.Cat"/>
<bean id="people" class="com.huang.autowiredtest.pojo.People" />
beans>
public class People {
@Autowired
@Qualifier(value = "dog111")
private Dog dog;
@Autowired
@Qualifier(value = "cat21")
private Cat cat;
private String name;
public Dog getDog() {
return dog;
}
public void setDog(Dog dog) {
this.dog = dog;
}
public Cat getCat() {
return cat;
}
public void setCat(Cat cat) {
this.cat = cat;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
注意:当配置了@autowired时候,set方法可以省略。
还有一个注解是@Resource(先通过bean名字去查找,然后通过名字去查找,都失败情况下报错,可以指定名字:@Resource(name=“xxx”))
都是用来自动装配的,放在属性字段上
@AutoWired通过byType,必须要求对象存在
@Resource是先通过byName注入,再byType注入
执行顺序不同:AutoWired默认通过byType的方式实现
Resource默认通过byname实现
@AutoWired如果不能唯一自动装配属性,则需要@qualifier(value=“xxxx”)配合实现
@Resource的作用相当于@Autowired,只不过@Autowired按byType自动注入
@Resource默认按 byName自动注入罢了。
@Resource有两个属性是比较重要的,分是name和type,Spring将@Resource注解的name属性解析为bean的名字,而type属性则解析为bean的类型。所以如果使用name属性,则使用byName的自动注入策略,而使用type属性时则使用byType自动注入策略。如果既不指定name也不指定type属性,这时将通过反射机制使用byName自动注入策略。
@Resource装配顺序
1. 如果同时指定了name和type,则从Spring上下文中找到唯一匹配的bean进行装配,找不到则抛出异常
2. 如果指定了name,则从上下文中查找名称(id)匹配的bean进行装配,找不到则抛出异常
3. 如果指定了type,则从上下文中找到类型匹配的唯一bean进行装配,找不到或者找到多个,都会抛出异常
4. 如果既没有指定name,又没有指定type,则自动按照byName方式进行装配;如果没有匹配,则回退为一个原始类型进行匹配,如果匹配则自动装配;
@Autowired 与@Resource的区别:
1、 @Autowired与@Resource都可以用来装配bean. 都可以写在字段上,或写在setter方法上。
2、 @Autowired默认按类型装配(这个注解是属业spring的),默认情况下必须要求依赖对象必须存在,如果要允许null值,可以设置它的required属性为false,
总结:
@Autowired//默认按type注入
@Qualifier(“cusInfoService”)//一般作为@Autowired()的修饰用
@Resource(name=“cusInfoService”)//默认按name注入,可以通过name和type属性进行选择性注入
一般@Autowired和@Qualifier一起用,@Resource单独用。
使用注解开发,必须保证aop包导入
//Component 组件
@Component
public class User {
public String name="huang";
}
<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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.huang.pojo"/>
<context:annotation-config/>
beans>
@Component
public class User {
@Value("黄宇航")
public String name;
}
<bean id="user" class="com.huang.pojo.User">
<property name="name" value="黄宇航"/>
bean>
这段代码就相当于上面的代码,value对应property
bean id=xxx对应于component注解
@component有几个衍生注解,在web开发中,会按照mvc三层架构分层
dao层 @Repository
service层 @service
controller @congtroller
这四个注解功能是一样的,都是代表将某个类注册到spring容器中,装配bean
@Autowired
@nullable
@resource
@qualifier
@Scope
单例模式
原型模式
//Component 组件
@Component
@Scope("singleton")
public class User {
@Value("黄宇航")
public String name;
}
xml与注解
xml与注解最佳实践:
<context:component-scan base-package="com.huang.pojo"/>
<context:annotation-config/>
完全不适用spring的xml配置了,全权交给java来做
javaConfig是Spring一个子项目,在Spring4之后,成为了一个核心内容。
为什么要学代理模式?因为这就是SpringAOP的底层【SpringAop和SpringMVC】
代理模式分类:
静态代理:
动态代理:
静态代理代码步骤:
1.接口
public interface Rent {
public void rent();
}
2.真实角色
public class LandLord implements Rent {
public void rent() {
System.out.println("房东要出租房子");
}
}
3.代理角色
//出了出租房子以外,其余皆是附属操作
public class Proxy implements Rent {
private LandLord landLord;
public Proxy(LandLord landLord) {
this.landLord = landLord;
}
public Proxy() {
}
//房东出租房子
public void rent() {
seeHouse();
landLord.rent();
contact();
fare();
}
public void seeHouse(){
System.out.println("看房子");
}
public void fare(){
System.out.println("收房费");
}
public void contact(){
System.out.println("签合同");
}
}
4.客户端访问代理角色
public static void main(String[] args) {
//房东要租房子
LandLord landLord=new LandLord();
//代理,中介帮房东租房子,但会有一些附属操作
Proxy proxy=new Proxy(landLord);
proxy.rent();
}
代理模式的好处:
可以使真是角色的操作更加纯粹,不用关注一些公共业务
公共就交给代理角色,实现业务的分工
公共业务发生扩展时候,方便集中管理
缺点:
一个真实角色就会产生一个代理角色;代码量会翻倍。开发效率会变低
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oCFkSaMl-1609411012089)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201209181811321.png)]
就是在不改变原有的代码基础上,实现新的方法
动态代理和静态代理角色一样
动态代理的代理类是动态生成的,不是我们直接写好的
动态代理分为两大类:基于接口的动态代理,基于类的动态代理。
需要了解两个类:Proxy:代理,InvocationHandler:调用处理程序
InvocationHandler:是一个接口,位于java.lang.reflect包下
动态代理:
public interface Rent {
public void rent();
}
//用这个类自动生成代理类
public class ProxyInvocationHandler implements InvocationHandler {
//被代理的接口
private Rent rent;
public void setRent(Rent rent) {
this.rent = rent;
}
//生成得到代理类
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(),rent.getClass().getInterfaces(),this);
}
//处理代理实例,并返回结果(处理代理的人)
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//动态代理的本质,就是使用反射机制实现
Object invoke = method.invoke(rent, args);
return invoke;
}
}
public class Client {
public static void main(String[] args) {
//真实角色
LandLord landLord=new LandLord();
//代理角色,现在没有
ProxyInvocationHandler pih=new ProxyInvocationHandler();
//通过调用程序处理角色来处理我们要调用的接口对象
pih.setRent(landLord);
Rent proxy = (Rent) pih.getProxy();//proxy是动态生成的,并没有写
proxy.rent();
}
}
改写:万能动态代理:
public interface IHuYaNan {
public void add();
public void delete();
public void update();
public void query();
}
public class HuYaNanImpl implements IHuYaNan {
public void add() {
System.out.println("add方法");
}
public void delete() {
System.out.println("delete方法");
}
public void update() {
System.out.println("update方法");
}
public void query() {
System.out.println("query方法");
}
}
//用这个类自动生成代理类
public class ProxyInvocationHandler implements InvocationHandler {
//被代理的接口
private Object target;
public void setTarget(Object target) {
this.target = target;
}
//生成得到代理类
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
}
//处理代理实例,并返回结果(处理代理的人)
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//动态代理的本质,就是使用反射机制实现
log(method.getName());
Object invoke = method.invoke(target, args);
return invoke;
}
public void log(String name){
System.out.println("debug:"+name);
}
}
public class Client {
public static void main(String[] args) {
HuYaNanImpl huYaNan=new HuYaNanImpl();
ProxyInvocationHandler proxyInvocationHandler=new ProxyInvocationHandler();
proxyInvocationHandler.setTarget(huYaNan);//设置要代理的对象
IHuYaNan proxy = (IHuYaNan) proxyInvocationHandler.getProxy();//注:是接口类型!
proxy.delete();
}
}
Proxy:s是生成动态代理实例的
InvocationHandler:调用处理程序并返回一个结果
动态代理好处:
创立接口,定义接口中的业务方法
public interface IUserService {
public void add();
public void delete();
public void update();
public void select();
}
实现接口中的方法
public class UserServiceImpl implements IUserService {
public void add() { System.out.println("add方法被调用了"); }
public void delete() { System.out.println("delete方法被调用了"); }
public void update() { System.out.println("update方法被调用了"); }
public void select() {System.out.println("select方法被调用了");}
}
定义log类
public class Log implements MethodBeforeAdvice {
//method:要执行的目标对象的方法;objects:参数 object:target
public void before(Method method, Object[] objects, Object o) throws Throwable {
System.out.println(o.getClass().getName()+"的"+method.getName()+"被执行了");
}
}
定义afterlog类
public class AfterLog implements AfterReturningAdvice {
//returnValue:返回值
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println(target.getClass().getName()+"的"+method.getName()+"被执行了;返回结果为"+returnValue);
}
}
定义配置文件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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--注册bean-->
<bean id="userService" class="service.UserServiceImpl" />
<bean id="log" class="log.Log"/>
<bean id="afterlog" class="log.AfterLog"/>
<!--aop配置导入aop约束-->
<!--方式一-->
<aop:config>
<!--切入点(在哪个地方执行我们需要的spring方法);expression:表达式 execution:要执行的位置(* * * * *) -->
<aop:pointcut id="pointcut" expression="execution(* service.UserServiceImpl.*(..))"/>
<!--执行环绕增加-->
<aop:advisor advice-ref="log" pointcut-ref="pointcut"/>
<aop:advisor advice-ref="afterlog" pointcut-ref="pointcut"/>
</aop:config>
</beans>
测试类
注意:★☆★☆★☆getbean返回的类型一定要转换成接口类型,而不是serviceimpl类型★☆★☆★☆★☆
public class AopTest {
@Test
public void aopTest(){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//动态代理代理的是一个接口
IUserService userService = (IUserService) context.getBean("userService");
userService.add();
}
}
步骤一:先自定义一个log类
public class DIYPointCut {
public void before(){
System.out.println("before被调用了");
}
public void after(){
System.out.println("after被调用了");
}
}
步骤二: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
https://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="DiyPointCut" class="diy.DIYPointCut"/>
步骤三:配置aop:config
<aop:config>
<!--这句话的意思是找到一个类的所有方法,并且不管有多少参数-->
<aop:pointcut id="pointcut" expression="execution(* service.UserServiceImpl.*(..))"/>
<aop:aspect ref="DiyPointCut">
<aop:after method="after" pointcut-ref="pointcut"/>
<aop:before method="before" pointcut-ref="pointcut"/>
</aop:aspect>
</aop:config>
</beans>
@Aspect //标注这个类是一个切面
public class AnnotationPointCut {
@After("execution(* service.UserServiceImpl.*(..))")
public void after(){
System.out.println("方法执行后");
}
@Before("execution(* service.UserServiceImpl.*(..))")
public void before(){
System.out.println("方法执行前");
}
@Around("execution(* service.UserServiceImpl.*(..))")
public void around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("环绕前");
// 获得签名
Signature signature=joinPoint.getSignature();
System.out.println("signature:"+signature);
Object proceed = joinPoint.proceed();
System.out.println("环绕后");
}
}
<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
https://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="userService" class="service.UserServiceImpl" />
<bean id="log" class="log.Log"/>
<bean id="afterlog" class="log.AfterLog"/>
<bean id="annotationPointCut" class="annotationpointcut.AnnotationPointCut"/>
<aop:aspectj-autoproxy />
beans>
public class AopTest {
@Test
public void aopTest(){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
IUserService userService = (IUserService) context.getBean("userService");
userService.add();
}
}
横切关注点:跨越应用程序多个模块的方法或功能。即是,与我们业务逻辑无关的,但是我们需要关注的部分,就是横切关注点,如:日志,安全,缓存,事务等等
切面(Aspect):横切关注点被模块化的特殊对象。 是一个类
通知(Advice):切面必须要完成的工作。 类中的一个方法
目标(Target):被通知对象
代理(Proxy):向目标对象应用通知之后创建的对象
切入点(PointCut):切面通知 执行的 地点 的定义
连接点(JointPoint):与切入点匹配的执行点
1.编写数据源配置
2.sqlsessionFactory
3.sqlSessionTemplate(线程安全且可以被多个映射器或者dao共享使用)
spring-dao.xml
<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
https://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="datasource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="username" value="root"/>
<property name="password" value="2580"/>
<property name="url" value="jdbc:mysql://localhost:3306/ee?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2B8&characterEncoding=UTF8"/>
bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="datasource"/>
<property name="configLocation" value="classpath:mybatis-config.xml"/>
bean>
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg index="0" ref="sqlSessionFactory"/>
bean>
beans>
/*
原先的mybatis中的配置文件mybatis-config.xml中的代码就可以省去,spring已经可以将其配置到spring配置中。
mybatis-config.xml只需要关注typeAliases,和mappers注册即可
*/
mybatis-config.xml
<configuration>
<typeAliases>
<package name="com.huang.pojo"/>
typeAliases>
<mappers>
<mapper resource="mapper/UserMapper.xml"/>
mappers>
configuration>
4.需要给接口加实现类[]
public interface IUserService {
public List<User> findAllUser();
}
public class UserServiceImpl implements IUserService {
//所有操作都使用session,现在都使用sqlsessionTemplate
private SqlSessionTemplate sqlSession;
public void setSqlSession(SqlSessionTemplate sqlSession) {
this.sqlSession = sqlSession;
}
public List<User> findAllUser() {
IUserService mapper = sqlSession.getMapper(IUserService.class);
List<User> allUser = mapper.findAllUser();
return allUser;
}
}
5.将自己写的实现类注入到spring中
applicationContext.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
//将spring-dao.xml配置文件导入到applicationContext.xml中,整合成一个配置文件
<import resource="spring-dao.xml"/>
<bean id="usermapper" class="com.huang.dao.UserServiceImpl">
<property name="sqlSession" ref="sqlSession"/>
bean>
beans>
6.测试使用
public class MybatisAndSpring {
@Test
public void test() throws IOException {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
IUserService userService = (IUserService) context.getBean("usermapper");
List<User> allUser = userService.findAllUser();
for (User user : allUser) {
System.out.println(user.getName());
}
}
事务ACID原则:
原子性
一致性
隔离性:多个业务可能操作同一个资源,防止数据损坏
持久性:事务一旦提交,无论系统发生什么问题,结果都不会收到影响,被持久化写入存储器中
声明式事务:AOP
编程式事务:需要在代码中,进行事务的管理
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6vub023J-1609411012091)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201203195455389.png)]
model模型(dao,service)
数据模型:提供要展示的数据,因此包含数据和行为,可以认为式领域模型或javaBean组件
view(视图jsp)
:负责进行模型的展示,一般就是用户界面
controller(servlet)
:接收用户请求,委托给模型进行处理(状态改变),处理完毕后吧返回的模型数据返回给视图,由视图负责展示(调度员作用)
前端 数据传输 实体类
实体类:用户名,密码。。。。。20个字段
登录功能:只需要用户名和密码,其余字段不需要,浪费
pojo细分:
pojo:User
vo:UserVo
dto:
特点:轻量级
高效
与spring兼容性好,无缝结合
约定大于配置
功能强大:RESTful,数据验证、格式化、本地化、主题等
简洁灵活
原理:
当发起请求时候被前置控制器拦截到请求,根据请求参数生成代理请求,找到请求对应的实际控制器,控制处理请求,创建数据模型,访问数据库,将模型响应给中心控制器,控制器使用模型与视图渲染视图结果,将结果返回给中心控制器,再将结果返回给请求者
@RequestMapping注解用于映射url到控制器或一个特定的处理程序方法。可用于类或方法上,用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。
1.概念:Restful就是一个资源定位及资源操作的风格,不是标准也不是协议,只是一种风格。基于这个风格设计的软件可以更加简洁,更有层次,更易于实现缓存等机制
功能:
资源:互联网所有的事物都可以被抽象为资源
资源操作:使用POST,DELETE,PUT,GET使用不同方法对资源进行操作
分别对应:添加、删除、修改、查询
2.传统方式操作资源:通过不同的参数来实现不同的效果,方法单一,post和get
3.使用Restful操作资源:可以通过不同的请求方式来实现不同的效果!如下:请求地址一样,但功能可以不同
4.在SpringMVC中可以使用@PathVariable注解,让方法参数的值对应绑定到一个URL模板变量上
未加@pathvariable注解之前
@Controller
public class RestfulController {
//原路径 http://localhost:8080/huang/add?a=1&b=2 执行是成功的
@RequestMapping("/add")
public String restfulTest(int a,int b,Model model){
int res=a+b;
model.addAttribute("msg","结果是"+res);
return "restful";
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZV3xM5Fv-1609411048537)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201226160420168.png)]
加了注解@PathVariable
路径未http://localhost:8080/abb/1/2
@RequestMapping("/abb/{a}/{b}")
public String restfulTest1(@PathVariable int a,@PathVariable int b,Model model{
int res=a+b;
model.addAttribute("msg","结果"+res);
return "restful";
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UWrD5zXC-1609411048540)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201226161221719.png)]
value与path作用相同,但当把value换成name,资源访问失败,找不到资源
方式1
@RequestMapping(value = "/add/{a}/{b}",method = RequestMethod.GET)
public String test2(@PathVariable int a,@PathVariable int b,Model model){
int res=a+b;
model.addAttribute("msg","test2的结果为"+res);
return "restful";
}
方式2
@RequestMapping(path = "/add/{a}/{b}",method = RequestMethod.GET)
public String test2(@PathVariable int a,@PathVariable int b,Model model){
int res=a+b;
model.addAttribute("msg","test2的结果为"+res);
return "restful";
}
方式3
当没有value或者path时候,method方法不能使用,且不知道为什么路径后面会多个
@RequestMapping("/add/{a}/{b}")
public String test2(@PathVariable int a,@PathVariable int b,Model model){
int res=a+b;
model.addAttribute("msg","test2的结果为"+res);
return "restful";
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OeZ1TWac-1609411048541)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201226233204885.png)]
@RequestMapping(name = "/add/{a}/{b}",method = RequestMethod.GET)
public String test2(@PathVariable int a,@PathVariable int b,Model model){
int res=a+b;
model.addAttribute("msg","test2的结果为"+res);
return "restful";
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VHJ0jP7q-1609411048545)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201226232649141.png)]
ModelAndView
public class NoAnnocationController implements Controller {
public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
ModelAndView md=new ModelAndView();
md.addObject("msg","Hello,NoAnnotationController");
md.setViewName("/noController");
return md;
}
}
通过Request和Response
没有视图解析器时候
@Controller
public class RedirectOrRequest {
@RequestMapping("/test/t1")
public String test(Model model){
model.addAttribute("msg","test");
//转发
return "/WEB-INF/jsp/restful.jsp";
}
@RequestMapping("/test/t2")
public String test2(Model model){
model.addAttribute("msg","test2");
//转发 地址不变
return "forward:/WEB-INF/jsp/restful.jsp";
}
@RequestMapping("/test/t3")
public String test3(){
//重定向 地址栏会变化
return "redirect:/index.jsp";
}
}
当有视图解析器的时候
@Controller
public class RedirectOrRequest {
@RequestMapping("/test/t1")
public String test(Model model){
model.addAttribute("msg","test:转发");
//转发返回的字符串就是视图名,转发地址不变
return "restful";
}
@RequestMapping("/test/t2")
public String test2(Model model){
//重定向地址栏会发生变化
model.addAttribute("msg","test2:重定向");
return "redirect:/index.jsp";
}
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private int id;
private String name;
private int age;
}
@Controller
@RequestMapping("/user")
public class UserController {
@GetMapping("/t1")
public String test(String name, Model model){
//1.接收前端参数
System.out.println("接收前端参数"+name);
//2.将返回的结果传递给前端
model.addAttribute("msg",name);
//3.跳转视图
return "restful";
}
}
当网址站中的参数传递,当传递的参数名为name时候,可以完成传参,别的名字不行
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Vn14DtNo-1609411048547)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201227165111485.png)]
当name改成username时
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xMcanKtk-1609411048550)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201227165152258.png)]
如何能自定义名,让username也同样生效
@GetMapping("/t2")
public String tes2(@RequestParam("username") String name, Model model){
//1.接收前端参数
System.out.println("接收前端参数"+name);
//2.将返回的结果传递给前端
model.addAttribute("msg",name);
//3.跳转视图
return "restful";
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MOV36K2c-1609411048551)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201227165902749.png)]
当前端提交的是一个对象的时候,要求提交的表单域和对象的属性名一致,参数使用对象即可
@GetMapping("/t2")
public String test3(User user){
return "restful";
}
}
如果使用对象的话,前端传递的参数名和对象必须一致,否则就是null
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-N002lL31-1609411048553)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201227171927989.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CxMu62Ba-1609411048554)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201227172017209.png)]
数据显示到前端:
第一种
public class ControllerTest1 implements Controller{
public ModelAndView handleRequest(HttpServletRequest httpServletRequest,HttpServletResponse httpServletResponse){
ModelAndView md=new ModelAndView();
md.addObject("msg","Hello,NoAnnotationController");
md.setViewName("/noController");
return md;
}
}
第二种
@RequestMapping("/test/hello")
public String test(@RequestParam("username")String name.Model model){
//相当于req.setAttribute("name",name)
model.addAttribute("msg","test/hello");
System.out.println(name);
return "restful";
}
第三种
springmvc中的项目,来方法中配置了HttpServletRequest,HttpServletResponse设置编码为utf-8依旧不成功
@Controller
public class EncodingController {
@RequestMapping("/encode/test")
public String test1(Model model, String name, HttpServletRequest request, HttpServletResponse response) throws UnsupportedEncodingException {
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
System.out.println(name);
model.addAttribute("msg",name);
return "restful";
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tRbrLpc7-1609411048556)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201229222559793.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aLzy59Qm-1609411048556)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201229222613555.png)]
web.xml中
配置springmvc的过滤器
<filter>
<filter-name>encoding</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>encoding</filter-name>
<url-pattern>/*
★★★★★★★★★★★重点内容 ★★★★★★★★★★★
<url-pattern>/*
/*
/二者之间的区别
/*匹配所有的url,包括带有扩展名的,一般只用于在过滤器上
/是可以拦截“.js”,“.css”,".png"等静态资源的访问
除了能够处理静态资源外还能处理http缓存请求,媒体数据流,和文件下载简历
且项目中如果配置了/会覆盖掉tomcat默认的default servlet
当配置了/
有两种配置方式
第一种:
前后端分离时代:
后端部署后端:提供接口,提供数据
1.JSON(JavaScript Object Notation,JS对象标记):轻量级,文本格式(相当于java中的字符串),能够有效提升网络传输效率
对象表示为键值对,数据由逗号分隔
花括号保存对象
方括号保存数组
{”name“:"huangyunang"}
{”age“:"18"}
{”sex“:"男"}
2.JSON是javaScript对象的字符串表示法,使用文本表示一个JS对象的信息,本质是一个字符串
JSON和JavaScript对象互转
2.1)要实现从json字符串转换为javaScript对象使用JSON.parse()方法
2.2)要实现从javaScript对象转换为JSON字符串,使用JSON.stringify()方法
前端独立部署,负责渲染后端的数据
步骤一
创建一个静态html,与index.jsp同目录
遇到的问题:静态资源访问不到
动态资源可以访问
解决问题:在web.xml文件中加入
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.html</url-pattern>
</servlet-mapping>
步骤二:
var user={
name:"黄宇航",
age:3,
sex:"男"
};
//将js对象转为json对象
var s = JSON.stringify(user);
//将json转为js对象
var parse = JSON.parse(s);
console.log(s);
console.log(parse);
</script>
步骤一
创建User实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private String name;
private String sex;
private int age;
}
<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">
<servlet>
<servlet-name>springmvcservlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
<init-param>
<param-name>contextConfigLocationparam-name>
<param-value>classpath:springmvc-servletparam-value>
init-param>
<load-on-startup>1load-on-startup>
servlet>
<servlet-mapping>
<servlet-name>springmvcservlet-name>
<url-pattern>/url-pattern>
servlet-mapping>
<servlet-mapping>
<servlet-name>defaultservlet-name>
<url-pattern>*.htmlurl-pattern>
servlet-mapping>
<filter>
<filter-name>encodingfilter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilterfilter-class>
<init-param>
<param-name>encodingparam-name>
<param-value>utf-8param-value>
init-param>
filter>
<filter-mapping>
<filter-name>encodingfilter-name>
<url-pattern>/*url-pattern>
filter-mapping>
web-app>
springmvc-servlet.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:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://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/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<context:component-scan base-package="com.huang.controller" />
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
<mvc:annotation-driven />
</beans>
UserController
@Controller
public class UserController {
@RequestMapping("/json")
@ResponseBody//加了这个注解,就不会走视图解析器,直接返回一个字符串
public String jsonTest(){
//创建一个对象
User user=new User("黄宇航","男",18);
return user.toString();
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0aSrQq51-1609411048558)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230221727343.png)]
将数据转为json
UserController
@Controller
public class UserController {
@RequestMapping("/json")
@ResponseBody//加了这个注解,就不会走视图解析器,直接返回一个字符串
public String jsonTest() throws JsonProcessingException {
ObjectMapper mapper=new ObjectMapper();
//创建一个对象
User user=new User("黄宇航","男",18);
String str = mapper.writeValueAsString(user);
return str;
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EgB2zSev-1609411048559)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230222116753.png)]
@Controller
public class UserController {
第一种方式:在注解上加入produces属性
@RequestMapping(value="/json",produces = "application/json;charset=utf-8")
@ResponseBody//加了这个注解,就不会走视图解析器,直接返回一个字符串
public String jsonTest() throws JsonProcessingException {
ObjectMapper mapper=new ObjectMapper();
//创建一个对象
User user=new User("黄宇航","男",18);
String str = mapper.writeValueAsString(user);
return str;
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mdBMAauj-1609411048560)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230222511510.png)]
springmvc-servlet.xml
第二种方式:
加入固定配置,只要使用json
<!--Json乱码问题配置-->
<mvc:annotation-driven >
<mvc:message-converters register-defaults="true">
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<constructor-arg value="UTF-8"/>
</bean>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="objectMapper">
<bean class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean">
<property name="failOnEmptyBeans" value="false"/>
</bean>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
@Controller
public class UserController {
@RequestMapping(value="/json")
@ResponseBody//加了这个注解,就不会走视图解析器,直接返回一个字符串
public String jsonTest() throws JsonProcessingException {
ObjectMapper mapper=new ObjectMapper();
//创建一个对象
User user=new User("黄宇航","男",18);
String str = mapper.writeValueAsString(user);
return str;
}
}
@RestController
下面的所有方法都只会返回json字符串,不加这个@ResponseBody注解
@Controller是返回视图解析器 与@ResponseBody配合使用返回json字符串
json一个字符串
@Controller
public class UserController {
// 字符串
@RequestMapping("/json")
@ResponseBody//加了这个注解,就不会走视图解析器,直接返回一个字符串
public String jsonTest() throws JsonProcessingException {
ObjectMapper mapper=new ObjectMapper();
//创建一个对象
User user=new User("黄宇航","男",18);
String str = mapper.writeValueAsString(user);
return str;
}
json一个数组
// 数组
@RequestMapping("/json2")
@ResponseBody
public String jsonTest2() throws JsonProcessingException {
ObjectMapper mapper=new ObjectMapper();
List<User> users=new ArrayList<User>();
User user1=new User("胡雅楠","25",2);
User user2=new User("黄宇航","25",2);
User user3=new User("施叶","25",2);
User user4=new User("杨琪","25",2);
User user5=new User("颜钰静","25",2);
users.add(user1);
users.add(user2);
users.add(user3);
users.add(user4);
users.add(user5);
String s = mapper.writeValueAsString(users);
return s;
}
//时间戳
json一个时间戳
@RequestMapping("/json3")
@ResponseBody
public String jsonTest3() throws JsonProcessingException {
ObjectMapper mapper=new ObjectMapper();
Date date=new Date();
//自定义日期格式
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//ObjectMapper,时间解析后的默认格式为:Timestamp。时间戳
// return mapper.writeValueAsString(date);
return mapper.writeValueAsString(sdf.format(date));
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-p5WLdxiI-1609411048562)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230230059063.png)]
另一种时间戳方式
//时间戳
@RequestMapping("/json4")
@ResponseBody
public String jsonTest4() throws JsonProcessingException {
ObjectMapper mapper=new ObjectMapper();
mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS,false);
//自定义日期格式
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
mapper.setDateFormat(sdf);
Date date=new Date();
return mapper.writeValueAsString(sdf.format(date));
}
与上面等同
后述还在自学中,第一次整理,有部分缺少,后续补上,激励 一下,哎嘿嘿