IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> 搭建Spring Boot2.X集成Hibernate5项目,并集成传统SSH老项目的安全认证组件,以Spring Boot方式开发项目并集成到老系统 -> 正文阅读

[Java知识库]搭建Spring Boot2.X集成Hibernate5项目,并集成传统SSH老项目的安全认证组件,以Spring Boot方式开发项目并集成到老系统

场景

由于老项目(SSH架构)需要新添加功能模块,习惯了Spring Boot快速开发,突然使用XML那一套东西,不是不可以,但是不爽,故想使用Spring Boot方式开发新项目集成到老系统。

同时,记录、分享在搭建、集成方面遇到的问题。

可行性分析

1.能否集成?

传统项目(SSH架构)那一套就是XML的配置,Spring Boot则是将XML简化,也无非类似,且新Spring Boot项目核心是提供接口被调用。故只要能保证开发的Spring Boot项目能成功集成到SSH老系统即可。

2.安全如何认证?

老项目存在权限认证组件,新开发的Spring Boot项目肯定得做集成,由老系统的认证组件进行安全认证。老系统的安全认证组件是非SpringBoot开发,但是以Jar的形式提供使用,最大问题在于相关配置文件中的对象的初始化以及兼容性问题需要考虑。

3.如何进行 ?

由于老系统使用Hibernate,所以首先就需要搭建Spring Boot集成Hibernate项目。

Hibernate没有Spring Boot的相关启动器,做集成稍显麻烦,但是万变不离其中,毕竟Spring Boot都是从xml转变过来的。

其次在搭建好的环境基础上引入老系统的安全认证组件进行测试。

搭建Spring Boot集成Hibernate5项目

添加依赖

JPA的默认实现是Hibernate,直接引入spring-boot-starter-data-jpa启动器即可。

      <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>

Entity

创建一个User对象,与数据库数据表映射。

@Entity
@Data
@Table(name="user")
public class User {
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private Integer id;
	private String name;
	private Integer age;
}

Dao

注意:低版本的Hibernate(应该是5以下)使用sessionFactory对象获取会话对象,高版本使用的是EntityManagerFactory对象。由于老项目肯定使用sessionFactory对象,所以集成测试也使用sessionFactory对象,此时sessionFactory是有警告。

public interface IUserDao {

    /**
     * @description: 保存用户
     **/
    void saveUser(User user);
    
    User getUser(Integer id);
}

@Repository
public class UserDaoImpl implements IUserDao {
    @Autowired
    private SessionFactory sessionFactory;

    Session getCurrentSession() {
        return sessionFactory.getCurrentSession();
    }

    @Override
    public void saveUser(User user) {
        getCurrentSession().save(user);
    }
    
    @Override
    public User getUser(Integer id) {
        return getCurrentSession().get(User.class, id);
    }
}

高版本中这样获取会话对象:

    @Autowired
    private EntityManagerFactory entityManagerFactory;

        Session getCurrentSession() {
            return entityManagerFactory.unwrap(SessionFactory.class).getCurrentSession();
    }

Service

public interface UserService {

    void mySave(User user);
    
    User  getUser(Integer id);
}

@Transactional(rollbackFor = Exception.class)
@Service
public class UserServiceImpl implements UserService {
	
	 @Autowired
	 private IUserDao userDao;
	 
	@Override
	public void mySave(User user) {
		userDao.saveUser(user);
	}
	
	@Override
	public User getUser(Integer id) {
		return userDao.getUser(id);
	}
}

Controller

@RestController
@RequestMapping("/test")
public class Controller {

    @Autowired
    private UserService userService;
    
    /**
     * 添加
     */
    @RequestMapping("/insert")
    public String insert() {
        User user = new User();
        user.setName("小白");
        user.setAge(22);
        userService.mySave(user);
        return "success";
    }
    
     /**
     * 查询
     */
    @RequestMapping("/get")
    public User getUser(Integer id) {
        return userService.getUser(id);
    }
}

配置application.properties

server.port=8888

#----------------------数据库配置------------------------------
spring.datasource.url=jdbc:mysql://localhost:3306/demo?characterEncoding=utf-8
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=123456

启动类

排除HibernateJpa相关的自动配置,进行手动配置,故需排除HibernateJpaAutoConfiguration自动配置类,否则报错如下:

org.springframework.orm.jpa.EntityManagerHolder cannot be cast to org.springframework.orm.hibernate5.SessionHolder
@SpringBootApplication(exclude = {HibernateJpaAutoConfiguration.class})
public class DemoApplication extends SpringBootServletInitializer {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

配置Hibernate

手动配置配置会话工厂与配置事务管理器,具体代码参考如下:

@Configuration
public class HibernateConfig {

    @Autowired
    private DataSource dataSource;


    /**
     * 配置会话工厂
     */
    @Bean(name = "sessionFactory")
//    @Bean(name="entityManagerFactory")
    public SessionFactory sessionFactoryBean() throws IOException {
        LocalSessionFactoryBean sessionFactoryBean = new LocalSessionFactoryBean();
        // 设置数据源
        sessionFactoryBean.setDataSource(dataSource);
        // entity包路径
        sessionFactoryBean.setPackagesToScan("cn.ybzy.demo.entity");
        // 配置hibernate属性
        Properties properties = new Properties();
        // sql方言
        properties.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQL5Dialect");
        // 自动创建|更新|验证数据库表结构
        properties.setProperty("hibernate.hbm2ddl.auto", "update");
        // 输出sql到控制台
        properties.setProperty("hibernate.show_sql", "true");
        // 打印漂亮的sql
        properties.setProperty("hibernate.format_sql", "true");
        properties.setProperty("hibernate.current_session_context_class", "org.springframework.orm.hibernate5.SpringSessionContext");
        sessionFactoryBean.setHibernateProperties(properties);
        sessionFactoryBean.afterPropertiesSet();
        SessionFactory sessionFactory = sessionFactoryBean.getObject();

        return sessionFactory;
    }


    /**
     * 配置事务管理器
     */
    @Bean(name = "transactionManager")
    public HibernateTransactionManager transactionManager(SessionFactory sessionFactory) {
        HibernateTransactionManager transactionManager = new HibernateTransactionManager();
        // 设置 sessionFactory
        transactionManager.setSessionFactory(sessionFactory);
        return transactionManager;
    }

    /**
     * 创建拦截器,配置事务拦截方式
     * 指定事务管理器和设置事务属性
     *
     * @return
     */
//    @Bean
//    public TransactionInterceptor transactionInterceptors(HibernateTransactionManager transactionManager) {
//        TransactionInterceptor transInterceptor = new TransactionInterceptor();
//        // 设置事务管理器
//        transInterceptor.setTransactionManager(transactionManager);
//        // 设置方法事务属性
//        Properties props = new Properties();
//        props.setProperty("save*", "PROPAGATION_REQUIRED");
//        props.setProperty("update*", "PROPAGATION_REQUIRED");
//        props.setProperty("delete*", "PROPAGATION_REQUIRED");
//        props.setProperty("find*", "PROPAGATION_REQUIRED,readOnly");
//        props.setProperty("get*", "PROPAGATION_REQUIRED,readOnly");
//        transInterceptor.setTransactionAttributes(props);
//        return transInterceptor;
//    }
//
//    /**
//     * AOP拦截配置
//     * 创建一个自动代理Bean的对象
//     */
//    @Bean
//    public BeanNameAutoProxyCreator beanNameAutoProxyCreator() {
//        BeanNameAutoProxyCreator beanNameAutoProxyCreator = new BeanNameAutoProxyCreator();
//        // 设置应该自动被代理包装的 bean 的名称
//        beanNameAutoProxyCreator.setBeanNames("*ServiceImpl");
//        // 设置常用拦截器
//        beanNameAutoProxyCreator.setInterceptorNames("transactionInterceptor");
//        return beanNameAutoProxyCreator;
//    }

}

进行测试

1.执行新增测试
在这里插入图片描述
2.执行查询测试
在这里插入图片描述
3.执行新增异常事务回滚测试

Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.

Mon Aug 15 14:44:05 CST 2022
There was an unexpected error (type=Internal Server Error, status=500).
/ by zero
java.lang.ArithmeticException: / by zero
	at cn.ybzy.demo.service.impl.MyUserServiceImpl.saveUser(MyUserServiceImpl.java:25)
	at cn.ybzy.demo.service.impl.MyUserServiceImpl$$FastClassBySpringCGLIB$$f77af9f1.invoke(<generated>)
	at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:771)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)
	at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:367)
	at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:118)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)
	at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:691)
	at cn.ybzy.demo.service.impl.MyUserServiceImpl$$EnhancerBySpringCGLIB$$a2877662.saveUser(<generated>)

当上述测试验证操作完成后进行安全认证组件集成。

集成安全认证组件

集成分析

由于添加的安全认证组件涉及到了2个xml配置文件

spring-shiro.xml

spring-datasource-jedis.xml

xml文件里面创建的Bean需要通过Spring Boot的方式添加到容器中

解决方案:

1.使用@ImportResource注解将原生配置文件引入,进行自动配置其中定义的Bean

2.参考xml中的配置,将xml配置转换成类配置

开始集成

这里使用第一种方案。由于引入组件中定义了一些对象,如service类 Dao类,这些对象需要加入到Spring容器中,所以使用@ComponentScan(basePackages = {"com.XX"})方式进行扫描

@ImportResource(locations = {"classpath:spring-shiro.xml","classpath:spring-datasource-jedis.xml"})
@ComponentScan(basePackages = {"com.XXX"})
@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

启动报错

Description:

Field sessionFactory in com.zhunda.base.dao.impl.UserDaoImpl required a bean of type 'org.hibernate.SessionFactory' that could not be found.

The injection point has the following annotations:
	- @org.springframework.beans.factory.annotation.Autowired(required=true)


Action:

Consider defining a bean of type 'org.hibernate.SessionFactory' in your configuration.

原因如下:

进行Spring扫描时,发现老项目Dao层中的需要SessionFactory对象,毕竟需要该对象操作数据库,但是此刻配置HibernateConfig对象未生效,故找不到

解决方案:将@ComponentScan(basePackages = {"com.XXX"})从启动类移动到HibernateConfig

@Configuration
@ComponentScan(basePackages = {"com.XXX"})
public class HibernateConfig {

}

再次出现异常:

Caused by: org.springframework.context.annotation.ConflictingBeanDefinitionException: Annotation-specified bean name 'userDaoImpl' for bean class [com.zhunda.base.dao.impl.UserDaoImpl] conflicts with existing, non-compatible bean definition of same name and class [cn.ybzy.demo.repository.impl.UserDaoImpl]

原因:

认证组件中定义有UserDaoImpl类与新项目中定义的测试UserDaoImpl类冲突,故将Spring Boot项目中的相关的测试对象,如UserDaoImpl改个名称

public interface IMyUserDao {

    /**
     * @description: 保存用户
     **/
    void saveUser(User user);
}


@Repository
public class MyUserDaoImpl implements IMyUserDao {
    @Autowired
    private SessionFactory sessionFactory;

    Session getCurrentSession() {
        return sessionFactory.getCurrentSession();
    }


    @Override
    public void saveUser(User user) {
        getCurrentSession().save(user);
    }
}

启动成功

2022-08-05 14:49:52.611  INFO 3048 --- [  restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8888 (http) with context path ''
2022-08-05 14:49:52.613  INFO 3048 --- [  restartedMain] o.s.s.quartz.SchedulerFactoryBean        : Starting Quartz Scheduler now
2022-08-05 14:49:52.613  INFO 3048 --- [  restartedMain] org.quartz.core.QuartzScheduler          : Scheduler quartzScheduler_$_NON_CLUSTERED started.
2022-08-05 14:49:52.626  INFO 3048 --- [  restartedMain] s.a.ScheduledAnnotationBeanPostProcessor : No TaskScheduler/ScheduledExecutorService bean found for scheduled processing
2022-08-05 14:49:52.635  INFO 3048 --- [  restartedMain] cn.ybzy.demo.DemoApplication             : Started DemoApplication in 7.301 seconds (JVM running for 8.798)

测试验证

接着测试权限认证是否正常。由于认证组件使用Shiro,故此处Shiro报错,集成认证组件出现异常

org.apache.shiro.UnavailableSecurityManagerException: No SecurityManager accessible to the calling code, either bound to the org.apache.shiro.util.ThreadContext or as a vm static singleton.  This is an invalid application configuration.

经过一番折腾,在配置delegatingFilterProxy对象即可解决

@ImportResource(locations = {"classpath:spring-shiro.xml","classpath:spring-datasource-jedis.xml"})
@SpringBootApplication
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

    @Bean
    public ShiroFilterFactoryBean delegatingFilterProxy(@Qualifier("shiroFilter") ShiroFilterFactoryBean shiroFilterFactoryBean) {
        return shiroFilterFactoryBean;
    }
}

启动项目,执行测试,成功拦截
在这里插入图片描述
访问登录接口,得到安全组件设置的cookie值:

set-cookie	SSO-SESSIONID=eb22cc107b094fb2ae5884a8df7923f4; Path=/; HttpOnly; SameSite=lax

将cookie值添加到集成项目对应的浏览器中
在这里插入图片描述
执行新增操作
在这里插入图片描述

执行查询操作
在这里插入图片描述
执行事务操作

	@Override
	public void mySave(User user) {
		userDao.saveUser(user);
		int a=1/0;
	}

程序异常,同时数据库事务生效。
在这里插入图片描述

使用JPA功能

Dao

创建相关接口继承CrudRepository对象

@Repository
public interface IUserRepository extends CrudRepository<User, Integer> {}

Service

@Transactional(rollbackFor = Exception.class)
@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private IUserDao userDao;

    @Autowired
    private IUserRepository userRepository;


    @Override
    public void saveUser(User user) {
//        userDao.saveUser(user);
        userRepository.save(user);
        int a = 1 / 0;
    }

    @Override
    public User getUser(Integer id) {
//        return userDao.getUser(id);
        Optional<User> optional = userRepository.findById(id);
        return optional.get();
    }
}

配置application.properties

server.port=8888

#----------------------数据库配置------------------------------
spring.datasource.url=jdbc:mysql://localhost:3306/demo?characterEncoding=utf-8
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=123456

#----------------------JPA配置------------------------------
# 数据库类型
spring.jpa.database=MySQL
# 打印sql语句
spring.jpa.show-sql=true
# 生成SQL表
spring.jpa.generate-ddl=true
# 自动修改表结构
spring.jpa.hibernate.ddl-auto=update

启动项目

启动报错:

Description:

Field userRepository in cn.ybzy.demo.service.impl.UserServiceImpl required a bean named 'entityManagerFactory' that could not be found.

The injection point has the following annotations:
	- @org.springframework.beans.factory.annotation.Autowired(required=true)


Action:

Consider defining a bean named 'entityManagerFactory' in your configuration.

默认情况下,JPA通过名称entityManagerFactory搜索sessionFactory

手动设置:方法上添加 @Bean(name="entityManagerFactory")

自动设置:方法名字一定要是entityManagerFactory

Hibernate配置

    /**
     * 配置会话工厂
     */
//   @Bean(name = "sessionFactory")
	@Bean(name="entityManagerFactory")
    public SessionFactory sessionFactoryBean() throws IOException {
        LocalSessionFactoryBean sessionFactoryBean = new LocalSessionFactoryBean();
        // 设置数据源
        sessionFactoryBean.setDataSource(dataSource);
        // entity包路径
        sessionFactoryBean.setPackagesToScan("cn.ybzy.demo.entity");
        // 配置hibernate属性
        Properties properties = new Properties();
        // sql方言
        properties.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQL5Dialect");
        // 自动创建|更新|验证数据库表结构
        properties.setProperty("hibernate.hbm2ddl.auto", "update");
        // 输出sql到控制台
        properties.setProperty("hibernate.show_sql", "true");
        // 打印漂亮的sql
        properties.setProperty("hibernate.format_sql", "true");
        properties.setProperty("hibernate.current_session_context_class", "org.springframework.orm.hibernate5.SpringSessionContext");
        sessionFactoryBean.setHibernateProperties(properties);
        sessionFactoryBean.afterPropertiesSet();
        SessionFactory sessionFactory = sessionFactoryBean.getObject();

        return sessionFactory;
    }

获取会话

在JPA中通常使用EntityManagerFactory对象获取会话。

    @Autowired
    private EntityManagerFactory entityManagerFactory;

        Session getCurrentSession() {
            return entityManagerFactory.unwrap(SessionFactory.class).getCurrentSession();
    }

执行测试

最后进行测试,JPA功能正常。

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-10-17 12:18:51  更:2022-10-17 12:23:27 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2025年1日历 -2025/1/30 14:07:16-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码