SpringBoot整合SpringSecurity

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: SpringBoot整合SpringSecurity

主页:写程序的小王叔叔的博客欢迎来访👀

支持:点赞收藏关注


1、说明

SpringSecurity是一个用于Java 企业级应用程序的安全框架,主要包含用户认证和用户授权两个方面.相比较Shiro而言,Security功能更加的强大,它可以很容易地扩展以满足更多安全控制方面的需求,但也相对它的学习成本会更高,两种框架各有利弊.实际开发中还是要根据业务和项目的需求来决定使用哪一种.

JWT是在Web应用中安全传递信息的规范,从本质上来说是Token的演变,是一种生成加密用户身份信息的Token,特别适用于分布式单点登陆的场景,无需在服务端保存用户的认证信息,而是直接对Token进行校验获取用户信息,使单点登录更为简单灵活.

2、项目环境

SpringBoot版本:2.1.6

SpringSecurity版本: 5.1.5

MyBatis-Plus版本: 3.1.0

JDK版本:1.8

数据表(SQL文件在项目中): 数据库中测试号的密码进行了加密,密码皆为123456:


Maven依赖如下:

<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><scope>runtime</scope></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!--Security依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></dependency><!-- MybatisPlus 核心库 --><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.1.0</version></dependency><!-- 引入阿里数据库连接池 --><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.1.6</version></dependency><!-- StringUtilS工具 --><dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId><version>3.5</version></dependency><!-- JSON工具 --><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.45</version></dependency><!-- JWT依赖 --><dependency><groupId>org.springframework.security</groupId><artifactId>spring-security-jwt</artifactId><version>1.0.9.RELEASE</version></dependency><dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.9.0</version></dependency></dependencies>

配置如下:

# 配置端口server:  port: 8764spring:# 配置数据源  datasource:    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/sans_security?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=false
    username: root
    password: 123456    type: com.alibaba.druid.pool.DruidDataSource
# JWT配置jwt:# 密匙KEY  secret: JWTSecret
# HeaderKEY  tokenHeader: Authorization
# Token前缀字符  tokenPrefix: Sans-
# 过期时间 单位秒 1天后过期=86400 7天后过期=604800  expiration: 86400# 配置不需要认证的接口  antMatchers: /index/**,/login/**,/favicon.ico
# Mybatis-plus相关配置mybatis-plus:# xml扫描,多个目录用逗号或者分号分隔(告诉 Mapper 所对应的 XML 文件位置)  mapper-locations: classpath:mapper/*.xml
# 以下配置均有默认值,可以不设置  global-config:    db-config:#主键类型 AUTO:"数据库ID自增" INPUT:"用户输入ID",ID_WORKER:"全局唯一ID (数字类型唯一ID)", UUID:"全局唯一ID UUID";      id-type: AUTO
#字段策略 IGNORED:"忽略判断" NOT_NULL:"非 NULL 判断") NOT_EMPTY:"非空判断"      field-strategy: NOT_EMPTY
#数据库类型      db-type: MYSQL
  configuration:# 是否开启自动驼峰命名规则映射:从数据库列名到Java属性驼峰命名的类似映射    map-underscore-to-camel-case: true# 返回map时true:当查询数据为空时字段返回为null,false:不加这个查询数据为空时,字段将被隐藏    call-setters-on-nulls: true# 这个配置会将执行的sql打印出来,在开发或测试的时候可以用    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

3、编写项目基础类

Entity,Dao,Service,及等SpringSecurity用户的Entity,Service类等在这里省略,请参考源码

编写JWT工具类

/*** JWT工具类*/@Slf4jpublicclassJWTTokenUtil {
publicstaticStringcreateAccessToken(SelfUserEntityselfUserEntity){
// 登陆成功生成JWTStringtoken=Jwts.builder()
// 放入用户名和用户ID                .setId(selfUserEntity.getUserId()+"")
// 主题                .setSubject(selfUserEntity.getUsername())
// 签发时间                .setIssuedAt(newDate())
// 签发者                .setIssuer("sans")
// 自定义属性 放入用户拥有权限                .claim("authorities", JSON.toJSONString(selfUserEntity.getAuthorities()))
// 失效时间                .setExpiration(newDate(System.currentTimeMillis() +JWTConfig.expiration))
// 签名算法和密钥                .signWith(SignatureAlgorithm.HS512, JWTConfig.secret)
                .compact();
returntoken;
    }
}

编写暂无权限处理类

@ComponentpublicclassUserAuthAccessDeniedHandlerimplementsAccessDeniedHandler{
@Overridepublicvoidhandle(HttpServletRequestrequest, HttpServletResponseresponse, AccessDeniedExceptionexception){
ResultUtil.responseJson(response,ResultUtil.resultCode(403,"未授权"));
    }
}

编写登录失败处理类

@Slf4j@ComponentpublicclassUserLoginFailureHandlerimplementsAuthenticationFailureHandler {
@OverridepublicvoidonAuthenticationFailure(HttpServletRequestrequest, HttpServletResponseresponse, AuthenticationExceptionexception){
// 这些对于操作的处理类可以根据不同异常进行不同处理if (exceptioninstanceofUsernameNotFoundException){
log.info("【登录失败】"+exception.getMessage());
ResultUtil.responseJson(response,ResultUtil.resultCode(500,"用户名不存在"));
        }
if (exceptioninstanceofLockedException){
log.info("【登录失败】"+exception.getMessage());
ResultUtil.responseJson(response,ResultUtil.resultCode(500,"用户被冻结"));
        }
if (exceptioninstanceofBadCredentialsException){
log.info("【登录失败】"+exception.getMessage());
ResultUtil.responseJson(response,ResultUtil.resultCode(500,"用户名密码不正确"));
        }
ResultUtil.responseJson(response,ResultUtil.resultCode(500,"登录失败"));
    }
}

编写登录成功处理类

@Slf4j@ComponentpublicclassUserLoginSuccessHandlerimplementsAuthenticationSuccessHandler {
@OverridepublicvoidonAuthenticationSuccess(HttpServletRequestrequest, HttpServletResponseresponse, Authenticationauthentication){
// 组装JWTSelfUserEntityselfUserEntity= (SelfUserEntity) authentication.getPrincipal();
Stringtoken=JWTTokenUtil.createAccessToken(selfUserEntity);
token=JWTConfig.tokenPrefix+token;
// 封装返回参数Map<String,Object>resultData=newHashMap<>();
resultData.put("code","200");
resultData.put("msg", "登录成功");
resultData.put("token",token);
ResultUtil.responseJson(response,resultData);
    }
}

编写登出成功处理类

@ComponentpublicclassUserLogoutSuccessHandlerimplementsLogoutSuccessHandler {
@OverridepublicvoidonLogoutSuccess(HttpServletRequestrequest, HttpServletResponseresponse, Authenticationauthentication){
Map<String,Object>resultData=newHashMap<>();
resultData.put("code","200");
resultData.put("msg", "登出成功");
SecurityContextHolder.clearContext();
ResultUtil.responseJson(response,ResultUtil.resultSuccess(resultData));
    }
}

4、编写Security核心类

编写自定义登录验证类

@ComponentpublicclassUserAuthenticationProviderimplementsAuthenticationProvider {
@AutowiredprivateSelfUserDetailsServiceselfUserDetailsService;
@AutowiredprivateSysUserServicesysUserService;
@OverridepublicAuthenticationauthenticate(Authenticationauthentication) throwsAuthenticationException {
// 获取表单输入中返回的用户名StringuserName= (String) authentication.getPrincipal();
// 获取表单中输入的密码Stringpassword= (String) authentication.getCredentials();
// 查询用户是否存在SelfUserEntityuserInfo=selfUserDetailsService.loadUserByUsername(userName);
if (userInfo==null) {
thrownewUsernameNotFoundException("用户名不存在");
        }
// 我们还要判断密码是否正确,这里我们的密码使用BCryptPasswordEncoder进行加密的if (!newBCryptPasswordEncoder().matches(password, userInfo.getPassword())) {
thrownewBadCredentialsException("密码不正确");
        }
// 还可以加一些其他信息的判断,比如用户账号已停用等判断if (userInfo.getStatus().equals("PROHIBIT")){
thrownewLockedException("该用户已被冻结");
        }
// 角色集合Set<GrantedAuthority>authorities=newHashSet<>();
// 查询用户角色List<SysRoleEntity>sysRoleEntityList=sysUserService.selectSysRoleByUserId(userInfo.getUserId());
for (SysRoleEntitysysRoleEntity: sysRoleEntityList){
authorities.add(newSimpleGrantedAuthority("ROLE_"+sysRoleEntity.getRoleName()));
        }
userInfo.setAuthorities(authorities);
// 进行登录returnnewUsernamePasswordAuthenticationToken(userInfo, password, authorities);
    }
@Overridepublicbooleansupports(Class<?>authentication) {
returntrue;
    }
}

编写自定义PermissionEvaluator注解验证

@ComponentpublicclassUserPermissionEvaluatorimplementsPermissionEvaluator {
@AutowiredprivateSysUserServicesysUserService;
@OverridepublicbooleanhasPermission(Authenticationauthentication, ObjecttargetUrl, Objectpermission) {
// 获取用户信息SelfUserEntityselfUserEntity=(SelfUserEntity) authentication.getPrincipal();
// 查询用户权限(这里可以将权限放入缓存中提升效率)Set<String>permissions=newHashSet<>();
List<SysMenuEntity>sysMenuEntityList=sysUserService.selectSysMenuByUserId(selfUserEntity.getUserId());
for (SysMenuEntitysysMenuEntity:sysMenuEntityList) {
permissions.add(sysMenuEntity.getPermission());
        }
// 权限对比if (permissions.contains(permission.toString())){
returntrue;
        }
returnfalse;
    }
@OverridepublicbooleanhasPermission(Authenticationauthentication, SerializabletargetId, StringtargetType, Objectpermission) {
returnfalse;
    }
}

编写SpringSecurity核心配置类

@Configuration@EnableWebSecurity@EnableGlobalMethodSecurity(prePostEnabled=true) //开启权限注解,默认是关闭的publicclassSecurityConfigextendsWebSecurityConfigurerAdapter {
/*** 自定义登录成功处理器*/@AutowiredprivateUserLoginSuccessHandleruserLoginSuccessHandler;
/*** 自定义登录失败处理器*/@AutowiredprivateUserLoginFailureHandleruserLoginFailureHandler;
/*** 自定义注销成功处理器*/@AutowiredprivateUserLogoutSuccessHandleruserLogoutSuccessHandler;
/*** 自定义暂无权限处理器*/@AutowiredprivateUserAuthAccessDeniedHandleruserAuthAccessDeniedHandler;
/*** 自定义未登录的处理器*/@AutowiredprivateUserAuthenticationEntryPointHandleruserAuthenticationEntryPointHandler;
/*** 自定义登录逻辑验证器*/@AutowiredprivateUserAuthenticationProvideruserAuthenticationProvider;
@BeanpublicBCryptPasswordEncoderbCryptPasswordEncoder(){
returnnewBCryptPasswordEncoder();
    }
/*** 注入自定义PermissionEvaluator*/@BeanpublicDefaultWebSecurityExpressionHandleruserSecurityExpressionHandler(){
DefaultWebSecurityExpressionHandlerhandler=newDefaultWebSecurityExpressionHandler();
handler.setPermissionEvaluator(newUserPermissionEvaluator());
returnhandler;
    }
/*** 配置登录验证逻辑*/@Overrideprotectedvoidconfigure(AuthenticationManagerBuilderauth){
//这里可启用我们自己的登陆验证逻辑auth.authenticationProvider(userAuthenticationProvider);
    }
@Overrideprotectedvoidconfigure(HttpSecurityhttp) throwsException {
http.authorizeRequests()
//不进行权限验证的请求或资源(从配置文件中读取)               .antMatchers(JWTConfig.antMatchers.split(",")).permitAll()
//其他的需要登陆后才能访问                .anyRequest().authenticated()
                .and()
//配置未登录自定义处理类                .httpBasic().authenticationEntryPoint(userAuthenticationEntryPointHandler)
                .and()
//配置登录地址                .formLogin()
                .loginProcessingUrl("/login/userLogin")
//配置登录成功自定义处理类                .successHandler(userLoginSuccessHandler)
//配置登录失败自定义处理类                .failureHandler(userLoginFailureHandler)
                .and()
//配置登出地址                .logout()
                .logoutUrl("/login/userLogout")
//配置用户登出自定义处理类                .logoutSuccessHandler(userLogoutSuccessHandler)
                .and()
//配置没有权限自定义处理类                .exceptionHandling().accessDeniedHandler(userAuthAccessDeniedHandler)
                .and()
// 开启跨域                .cors()
                .and()
// 取消跨站请求伪造防护                .csrf().disable();
// 基于Token不需要sessionhttp.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
// 禁用缓存http.headers().cacheControl();
// 添加JWT过滤器http.addFilter(newJWTAuthenticationTokenFilter(authenticationManager()));
    }
}

5、编写JWT拦截类

编写JWT接口请求校验拦截器

/*** JWT接口请求校验拦截器* 请求接口时会进入这里验证Token是否合法和过期* @Author Sans* @CreateTime 2019/10/5 16:41*/@Slf4jpublicclassJWTAuthenticationTokenFilterextendsBasicAuthenticationFilter {
publicJWTAuthenticationTokenFilter(AuthenticationManagerauthenticationManager) {
super(authenticationManager);
    }
@OverrideprotectedvoiddoFilterInternal(HttpServletRequestrequest, HttpServletResponseresponse, FilterChainfilterChain) throwsServletException, IOException {
// 获取请求头中JWT的TokenStringtokenHeader=request.getHeader(JWTConfig.tokenHeader);
if (null!=tokenHeader&&tokenHeader.startsWith(JWTConfig.tokenPrefix)) {
try {
// 截取JWT前缀Stringtoken=tokenHeader.replace(JWTConfig.tokenPrefix, "");
// 解析JWTClaimsclaims=Jwts.parser()
                        .setSigningKey(JWTConfig.secret)
                        .parseClaimsJws(token)
                        .getBody();
// 获取用户名Stringusername=claims.getSubject();
StringuserId=claims.getId();
if(!StringUtils.isEmpty(username)&&!StringUtils.isEmpty(userId)) {
// 获取角色List<GrantedAuthority>authorities=newArrayList<>();
Stringauthority=claims.get("authorities").toString();
if(!StringUtils.isEmpty(authority)){
List<Map<String,String>>authorityMap=JSONObject.parseObject(authority, List.class);
for(Map<String,String>role : authorityMap){
if(!StringUtils.isEmpty(role)) {
authorities.add(newSimpleGrantedAuthority(role.get("authority")));
                            }
                        }
                    }
//组装参数SelfUserEntityselfUserEntity=newSelfUserEntity();
selfUserEntity.setUsername(claims.getSubject());
selfUserEntity.setUserId(Long.parseLong(claims.getId()));
selfUserEntity.setAuthorities(authorities);
UsernamePasswordAuthenticationTokenauthentication=newUsernamePasswordAuthenticationToken(selfUserEntity, userId, authorities);
SecurityContextHolder.getContext().setAuthentication(authentication);
                }
            } catch (ExpiredJwtExceptione){
log.info("Token过期");
            } catch (Exceptione) {
log.info("Token无效");
            }
        }
filterChain.doFilter(request, response);
return;
    }
}

6、权限注解和hasPermission权限扩展

Security允许我们在定义URL方法访问所应有的注解权限时使用SpringEL表达式,在定义所需的访问权限时如果对应的表达式返回结果为true则表示拥有对应的权限,反之则没有权限,会进入到我们配置的UserAuthAccessDeniedHandler(暂无权限处理类)中进行处理.这里举一些例子,代码中注释有对应的描述。


表达式

@PreAuthorize("hasRole('ADMIN')")
@RequestMapping(value="/info",method=RequestMethod.GET)
publicMap<String,Object>userLogin(){
Map<String,Object>result=newHashMap<>();
SelfUserEntityuserDetails=SecurityUtil.getUserInfo();
result.put("title","管理端信息");
result.put("data",userDetails);
returnResultUtil.resultSuccess(result);
    }
@PreAuthorize("hasAnyRole('ADMIN','USER')")
@RequestMapping(value="/list",method=RequestMethod.GET)
publicMap<String,Object>list(){
Map<String,Object>result=newHashMap<>();
List<SysUserEntity>sysUserEntityList=sysUserService.list();
result.put("title","拥有用户或者管理员角色都可以查看");
result.put("data",sysUserEntityList);
returnResultUtil.resultSuccess(result);
    }
@PreAuthorize("hasRole('ADMIN') and hasRole('USER')")
@RequestMapping(value="/menuList",method=RequestMethod.GET)
publicMap<String,Object>menuList(){
Map<String,Object>result=newHashMap<>();
List<SysMenuEntity>sysMenuEntityList=sysMenuService.list();
result.put("title","拥有用户和管理员角色都可以查看");
result.put("data",sysMenuEntityList);
returnResultUtil.resultSuccess(result);
    }

通常情况下使用hasRole和hasAnyRole基本可以满足大部分鉴权需求,但是有时候面对更复杂的场景上述常规表示式无法完成权限认证,Security也为我们提供了解决方案.通过hasPermission()来扩展表达式.使用hasPermission()首先要实现PermissionEvaluator接口


@ComponentpublicclassUserPermissionEvaluatorimplementsPermissionEvaluator {
@AutowiredprivateSysUserServicesysUserService;
@OverridepublicbooleanhasPermission(Authenticationauthentication, ObjecttargetUrl, Objectpermission) {
// 获取用户信息SelfUserEntityselfUserEntity=(SelfUserEntity) authentication.getPrincipal();
// 查询用户权限(这里可以将权限放入缓存中提升效率)Set<String>permissions=newHashSet<>();
List<SysMenuEntity>sysMenuEntityList=sysUserService.selectSysMenuByUserId(selfUserEntity.getUserId());
for (SysMenuEntitysysMenuEntity:sysMenuEntityList) {
permissions.add(sysMenuEntity.getPermission());
        }
// 权限对比if (permissions.contains(permission.toString())){
returntrue;
        }
returnfalse;
    }
@OverridepublicbooleanhasPermission(Authenticationauthentication, SerializabletargetId, StringtargetType, Objectpermission) {
returnfalse;
    }
}

在请求方法上添加hasPermission示例

@PreAuthorize("hasPermission('/admin/userList','sys:user:info')")
@RequestMapping(value="/userList",method=RequestMethod.GET)
publicMap<String,Object>userList(){
Map<String,Object>result=newHashMap<>();
List<SysUserEntity>sysUserEntityList=sysUserService.list();
result.put("title","拥有sys:user:info权限都可以查看");
result.put("data",sysUserEntityList);
returnResultUtil.resultSuccess(result);
    }

hasPermission可以也可以和其他表达式联合使用

@PreAuthorize("hasRole('ADMIN') and hasPermission('/admin/adminRoleList','sys:role:info')")
@RequestMapping(value="/adminRoleList",method=RequestMethod.GET)
publicMap<String,Object>adminRoleList(){
Map<String,Object>result=newHashMap<>();
List<SysRoleEntity>sysRoleEntityList=sysRoleService.list();
result.put("title","拥有ADMIN角色和sys:role:info权限可以访问");
result.put("data",sysRoleEntityList);
returnResultUtil.resultSuccess(result);
    }

7、测试

创建账户这里用户加密使用了Security推荐的bCryptPasswordEncoder方法

/*** 注册用户*/@TestpublicvoidcontextLoads() {
// 注册用户SysUserEntitysysUserEntity=newSysUserEntity();
sysUserEntity.setUsername("sans");
sysUserEntity.setPassword(bCryptPasswordEncoder.encode("123456"));
// 设置用户状态sysUserEntity.setStatus("NORMAL");
sysUserService.save(sysUserEntity);
// 分配角色 1:ADMIN 2:USERSysUserRoleEntitysysUserRoleEntity=newSysUserRoleEntity();
sysUserRoleEntity.setRoleId(2L);
sysUserRoleEntity.setUserId(sysUserEntity.getUserId());
sysUserRoleService.save(sysUserRoleEntity);
    }

登录USER角色账号,登录成功后我们会获取到身份认证的Token

访问USER角色的接口,把上一步获取到的Token设置在Headers中,Key为Authorization,我们之前实现的JWTAuthenticationTokenFilter拦截器会根据请求头中的Authorization获取并解析Token使用USER角色Token访问ADMIN角色的接口,会被拒绝,告知未授权(暂无权限会进入我们定义的UserAuthAccessDeniedHandler这个类进行处理)。更换ADMIN角色进行登录并访问ADMIN接口



⚠️注意 ~

💯本期内容就结束了,如果内容有误,麻烦大家评论区指出!

如有疑问❓可以在评论区💬或私信💬,尽我最大能力🏃‍♀️帮大家解决👨‍🏫!

如果我的文章有帮助到您,欢迎点赞+关注✔️鼓励博主🏃,您的鼓励是我分享的动力🏃🏃🏃~

相关实践学习
基于CentOS快速搭建LAMP环境
本教程介绍如何搭建LAMP环境,其中LAMP分别代表Linux、Apache、MySQL和PHP。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
19天前
|
监控 Java 应用服务中间件
spring和springboot的区别
spring和springboot的区别
20 1
|
2月前
|
存储 安全 Java
Spring Boot整合Spring Security--学习笔记
Spring Boot整合Spring Security--学习笔记
62 1
|
2月前
|
消息中间件 Cloud Native Java
【Spring云原生系列】SpringBoot+Spring Cloud Stream:消息驱动架构(MDA)解析,实现异步处理与解耦合
【Spring云原生系列】SpringBoot+Spring Cloud Stream:消息驱动架构(MDA)解析,实现异步处理与解耦合
|
1月前
|
安全 数据安全/隐私保护
Springboot+Spring security +jwt认证+动态授权
Springboot+Spring security +jwt认证+动态授权
|
2月前
|
消息中间件 JSON Java
Spring Boot、Spring Cloud与Spring Cloud Alibaba版本对应关系
Spring Boot、Spring Cloud与Spring Cloud Alibaba版本对应关系
1139 0
|
13天前
|
SQL Java 数据库连接
Springboot框架整合Spring JDBC操作数据
JDBC是Java数据库连接API,用于执行SQL并访问多种关系数据库。它包括一系列Java类和接口,用于建立数据库连接、创建数据库操作对象、定义SQL语句、执行操作并处理结果集。直接使用JDBC涉及七个步骤,包括加载驱动、建立连接、创建对象、定义SQL、执行操作、处理结果和关闭资源。Spring Boot的`spring-boot-starter-jdbc`简化了这些步骤,提供了一个在Spring生态中更便捷使用JDBC的封装。集成Spring JDBC需要添加相关依赖,配置数据库连接信息,并通过JdbcTemplate进行数据库操作,如插入、更新、删除和查询。
|
13天前
|
SQL Java 数据库连接
Springboot框架整合Spring Data JPA操作数据
Spring Data JPA是Spring基于ORM和JPA规范封装的框架,简化了数据库操作,提供增删改查等接口,并可通过方法名自动生成查询。集成到Spring Boot需添加相关依赖并配置数据库连接和JPA设置。基础用法包括定义实体类和Repository接口,通过Repository接口可直接进行数据操作。此外,JPA支持关键字查询,如通过`findByAuthor`自动转换为SQL的`WHERE author=?`查询。
|
18天前
|
Java Maven Docker
0.07 秒启动一个 SpringBoot 项目!Spring Native 很强!!
0.07 秒启动一个 SpringBoot 项目!Spring Native 很强!!
26 2
|
19天前
|
Java Maven 数据库
Spring Boot Starter: 快速简明地创建Spring应用
Spring Boot Starter: 快速简明地创建Spring应用
|
20天前
|
Java Nacos 开发者
Java从入门到精通:4.2.1学习新技术与框架——以Spring Boot和Spring Cloud Alibaba为例
Java从入门到精通:4.2.1学习新技术与框架——以Spring Boot和Spring Cloud Alibaba为例