随便写一下,增删改查返回对应的字符

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
@RequestMapping("/security")
public class OauthBase {@GetMapping("/add")public String add(){return "add";}@GetMapping("/update")public String update(){return "update";}@GetMapping("/get")public String get(){return "get";}@GetMapping("/del")public String del(){return "del";}
}

基础认证配置类

import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.stereotype.Component;@Component
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {/*** 新增Security* 授权账户* @param auth* @throws Exception*/@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {/*** 账号、密码、接口权限*/auth.inMemoryAuthentication().withUser("mykt").password("mykt").authorities("/");}/*** 认证方式* @param http* @throws Exception*/@Overrideprotected void configure(HttpSecurity http) throws Exception {/*** 认证之后就能访问所有接口*/http.authorizeRequests().antMatchers("/**").fullyAuthenticated().and().httpBasic();}/*** 加密方式,恢复以前模式* @return*/@Beanpublic static NoOpPasswordEncoder PasswordEncoder(){return (NoOpPasswordEncoder)NoOpPasswordEncoder.getInstance();}
}

输入对应的账号密码就可以访问对应的接口,这个非常简单。

From表单验证

/*** 认证方式* @param http* @throws Exception*/@Overrideprotected void configure(HttpSecurity http) throws Exception {/*** 基础认证*///http.authorizeRequests().antMatchers("/**").fullyAuthenticated().and().httpBasic();/*** form表单验证*/http.authorizeRequests().antMatchers("/**").fullyAuthenticated().and().formLogin();}

效果图(账号密码没变,页面自带,不需要自己写)

配置权限规则(不同的账号对应不同的权限)

import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.stereotype.Component;@Component
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {/*** 新增Security* 授权账户* @param auth* @throws Exception*/@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {/*** 账号、密码、接口权限*/auth.inMemoryAuthentication().withUser("mykt-admin").password("mykt-admin").authorities("add","update","get","del");auth.inMemoryAuthentication().withUser("mykt-add").password("mykt-add").authorities("add");auth.inMemoryAuthentication().withUser("mykt-update").password("mykt-update").authorities("update");auth.inMemoryAuthentication().withUser("mykt-get").password("mykt-get").authorities("get");auth.inMemoryAuthentication().withUser("mykt-del").password("mykt-del").authorities("del");}/*** 认证方式* @param http* @throws Exception*/@Overrideprotected void configure(HttpSecurity http) throws Exception {/*** 基础认证*///http.authorizeRequests().antMatchers("/**").fullyAuthenticated().and().httpBasic();/*** form表单验证*///http.authorizeRequests().antMatchers("/**").fullyAuthenticated().and().formLogin();/*** 拦截规则*/http.authorizeRequests().antMatchers("/add").hasAnyAuthority("add").antMatchers("/get").hasAnyAuthority("get").antMatchers("/update").hasAnyAuthority("update").antMatchers("/del").hasAnyAuthority("del")//form验证.antMatchers("/**").fullyAuthenticated().and().formLogin();}/*** 加密方式,恢复以前模式* @return*/@Beanpublic static NoOpPasswordEncoder PasswordEncoder(){return (NoOpPasswordEncoder)NoOpPasswordEncoder.getInstance();}
}
创建了五个账号,mykt-admin、mykt-add 、mykt-update 、mykt-get 、mykt-del,那么从账号名称中就可以看出来这些账号对应的权限
mykt-add测试



mykt-admin测试




权限不足跳转页面
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.server.ErrorPage;
import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;@Configuration
public class WebServerAutoConfiguration {@Beanpublic ConfigurableServletWebServerFactory webServerFactroy(){TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();ErrorPage errorPage403 = new ErrorPage(HttpStatus.FORBIDDEN,"/error/403");ErrorPage errorPage404 = new ErrorPage(HttpStatus.NOT_FOUND,"/error/404");ErrorPage errorPage500 = new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR,"/error/500");factory.addErrorPages(errorPage403,errorPage404,errorPage500);return  factory;}}
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
public class ErrorController {@RequestMapping("/error/403")public String error403(){return "你当前访问的接口权限不足";}@RequestMapping("/error/404")public String error404(){return "资源不可用";}
}



为了演示效果, 正常的环境应该是返回码值,由前端对码值进行错误逻辑判断跳转到对应错误页面

自定义登陆页面

创建页面将html文件放在resource文件下面
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>登陆</title>
</head>
<body>
<h1>自定义登陆页面</h1><form action="/login" method="post"><span>用户名称</span><input type="text" name="username" /><br><span>用户密码</span><input type="password" name="password" /><br><input type="submit" value="登陆"></form>
</body>
</html>
指定登陆请求
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;/*** login请求*/
@Controller
public class LoginController {@RequestMapping("/login")public String login(){return "login";}}
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.stereotype.Component;@Component
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {/*** 新增Security* 授权账户* @param auth* @throws Exception*/@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {/*** 账号、密码、接口权限*/auth.inMemoryAuthentication().withUser("mykt-admin").password("mykt-admin").authorities("add","update","get","del");auth.inMemoryAuthentication().withUser("mykt-add").password("mykt-add").authorities("add");auth.inMemoryAuthentication().withUser("mykt-update").password("mykt-update").authorities("update");auth.inMemoryAuthentication().withUser("mykt-get").password("mykt-get").authorities("get");auth.inMemoryAuthentication().withUser("mykt-del").password("mykt-del").authorities("del");}/*** 认证方式* @param http* @throws Exception*/@Overrideprotected void configure(HttpSecurity http) throws Exception {/*** 基础认证*///http.authorizeRequests().antMatchers("/**").fullyAuthenticated().and().httpBasic();/*** form表单验证*///http.authorizeRequests().antMatchers("/**").fullyAuthenticated().and().formLogin();/*** 拦截规则*/http.authorizeRequests().antMatchers("/add").hasAnyAuthority("add").antMatchers("/get").hasAnyAuthority("get").antMatchers("/update").hasAnyAuthority("update").antMatchers("/del").hasAnyAuthority("del").antMatchers("/login").permitAll()//form验证.antMatchers("/**").fullyAuthenticated().and().formLogin()//添加自定义跳转页面.loginPage("/login").and().csrf().disable();}/*** 加密方式,恢复以前模式* @return*/@Beanpublic static NoOpPasswordEncoder PasswordEncoder(){return (NoOpPasswordEncoder)NoOpPasswordEncoder.getInstance();}
}

这个地方写的时候出现过一个问题,一直报个错误
Hint: This may be the result of an unspecified view, due to default view name generation
后面百度终于查到,说是没加一个包,加了就可以了
     <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency>

RBAC权限架构(多对多关联)


用户绑定角色,然后角色绑定权限,那么创建用户的时候,只要给用户选择对应的角色就赋予对应的权限,可以这样理解。

springsecurity整合RBAC权限架构

sql表

/*
Navicat MySQL Data TransferSource Server         : 127.0.0.1
Source Server Version : 50717
Source Host           : 127.0.0.1:3306
Source Database       : mayikt_rbacTarget Server Type    : MYSQL
Target Server Version : 50717
File Encoding         : 65001Date: 2021-05-25 04:17:30
*/SET FOREIGN_KEY_CHECKS=0;-- ----------------------------
-- Table structure for sys_permission
-- ----------------------------
DROP TABLE IF EXISTS `sys_permission`;
CREATE TABLE `sys_permission` (`id` int(10) NOT NULL,`permName` varchar(50) DEFAULT NULL,`permTag` varchar(50) DEFAULT NULL,`url` varchar(255) DEFAULT NULL COMMENT '请求url',PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;-- ----------------------------
-- Records of sys_permission
-- ----------------------------
INSERT INTO `sys_permission` VALUES ('1', '查询用户', 'getUser', '/getUser');
INSERT INTO `sys_permission` VALUES ('2', '添加用户', 'addUser', '/addUser');
INSERT INTO `sys_permission` VALUES ('3', '修改用户', 'updateUser', '/updateUser');
INSERT INTO `sys_permission` VALUES ('4', '删除用户', 'delUser', '/delUser');-- ----------------------------
-- Table structure for sys_role
-- ----------------------------
DROP TABLE IF EXISTS `sys_role`;
CREATE TABLE `sys_role` (`id` int(10) NOT NULL,`roleName` varchar(50) DEFAULT NULL,`roleDesc` varchar(50) DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;-- ----------------------------
-- Records of sys_role
-- ----------------------------
INSERT INTO `sys_role` VALUES ('1', 'admin', '管理员');
INSERT INTO `sys_role` VALUES ('2', 'add_user', '添加管理员');-- ----------------------------
-- Table structure for sys_role_permission
-- ----------------------------
DROP TABLE IF EXISTS `sys_role_permission`;
CREATE TABLE `sys_role_permission` (`role_id` int(10) DEFAULT NULL,`perm_id` int(10) DEFAULT NULL,KEY `FK_Reference_3` (`role_id`),KEY `FK_Reference_4` (`perm_id`),CONSTRAINT `FK_Reference_3` FOREIGN KEY (`role_id`) REFERENCES `sys_role` (`id`),CONSTRAINT `FK_Reference_4` FOREIGN KEY (`perm_id`) REFERENCES `sys_permission` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;-- ----------------------------
-- Records of sys_role_permission
-- ----------------------------
INSERT INTO `sys_role_permission` VALUES ('1', '1');
INSERT INTO `sys_role_permission` VALUES ('1', '2');
INSERT INTO `sys_role_permission` VALUES ('1', '3');
INSERT INTO `sys_role_permission` VALUES ('1', '4');
INSERT INTO `sys_role_permission` VALUES ('2', '2');-- ----------------------------
-- Table structure for sys_user
-- ----------------------------
DROP TABLE IF EXISTS `sys_user`;
CREATE TABLE `sys_user` (`id` int(10) NOT NULL,`username` varchar(50) DEFAULT NULL,`realname` varchar(50) DEFAULT NULL,`password` varchar(50) DEFAULT NULL,`createDate` date DEFAULT NULL,`lastLoginTime` date DEFAULT NULL,`enabled` int(5) DEFAULT NULL,`accountNonExpired` int(5) DEFAULT NULL,`accountNonLocked` int(5) DEFAULT NULL,`credentialsNonExpired` int(5) DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;-- ----------------------------
-- Records of sys_user
-- ----------------------------
INSERT INTO `sys_user` VALUES ('1', 'mayikt_admin', '张三', '99743025dc21f56c63d0cb2dd34f06f5', '2018-11-13', '2018-11-13', '1', '1', '1', '1');
INSERT INTO `sys_user` VALUES ('2', 'mayikt_add', '小余', 'a5a6996f2e1953161522a93cbb5fb556', '2018-11-13', '2018-11-13', '1', '1', '1', '1');-- ----------------------------
-- Table structure for sys_user_role
-- ----------------------------
DROP TABLE IF EXISTS `sys_user_role`;
CREATE TABLE `sys_user_role` (`user_id` int(10) DEFAULT NULL,`role_id` int(10) DEFAULT NULL,KEY `FK_Reference_1` (`user_id`),KEY `FK_Reference_2` (`role_id`),CONSTRAINT `FK_Reference_1` FOREIGN KEY (`user_id`) REFERENCES `sys_user` (`id`),CONSTRAINT `FK_Reference_2` FOREIGN KEY (`role_id`) REFERENCES `sys_role` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;-- ----------------------------
-- Records of sys_user_role
-- ----------------------------
INSERT INTO `sys_user_role` VALUES ('1', '1');
INSERT INTO `sys_user_role` VALUES ('2', '2');
然后就是SpringBoot整合mybatis(略)
那么我们现在要做的就是把以前写死的账号、密码、url都要通过查询数据动态的拿到,那么这个就是我们接下来要做的事情。
SecurityConfig
import com.my.mapper.PermissionMapper;
import com.my.model.PermissionModel;
import com.my.service.serviceimpl.MemberDetailsServiceimpl;
import com.my.utils.MD5Util;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;import java.util.List;@Component
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {@Autowiredprivate PermissionMapper permissionMapper;@Autowiredprivate MemberDetailsServiceimpl memberDetailsServiceimpl;/*** 新增Security* 授权账户* @param auth* @throws Exception*/@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.userDetailsService(memberDetailsServiceimpl).passwordEncoder(new PasswordEncoder() {/*** 对用户输入的密码进行加密* @param charSequence* @return*/@Overridepublic String encode(CharSequence charSequence) {String encode = MD5Util.encode((String) charSequence);return encode;}/*** 加密比对* @param charSequence 输入明文密码* @param password  数据库中的密码* @return true 登陆成功  false 密码错误*/@Overridepublic boolean matches(CharSequence charSequence, String password) {//输入的密码进行加密String rawPass = MD5Util.encode((String) charSequence);//对比密码return  password.equals(rawPass);}});}/*** 认证方式* @param http* @throws Exception*/@Overrideprotected void configure(HttpSecurity http) throws Exception {ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry authorizeRequests = http.authorizeRequests();//查询到所有的权限/*** sql* SELECT*     id,*     permName,*     permTag,*     url* FROM*     sys_permission*/List<PermissionModel> permissionList = permissionMapper.getPermissionList();permissionList.forEach(x->{//添加规则authorizeRequests.antMatchers(x.getUrl()).hasAnyAuthority(x.getPermTag());});authorizeRequests.antMatchers("/login").permitAll().antMatchers("/**").fullyAuthenticated().and().formLogin()//添加自定义跳转页面.loginPage("/login").and().csrf().disable();}/*** 加密方式,恢复以前模式* @return*/@Beanpublic static NoOpPasswordEncoder PasswordEncoder(){return (NoOpPasswordEncoder)NoOpPasswordEncoder.getInstance();}
}
重写UserDetailsService.loadUserByUsername方法
import com.my.mapper.PermissionMapper;
import com.my.mapper.UserMapper;
import com.my.model.PermissionModel;
import com.my.model.UserModel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component;import java.util.ArrayList;
import java.util.List;/*** 重写UserDetailsService.loadUserByUsername方法*/
@Component
public class MemberDetailsServiceimpl implements UserDetailsService {@Autowiredprivate UserMapper userMapper;@Autowiredprivate PermissionMapper permissionMapper;@Overridepublic UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {//根据登陆的userName查询这个用户/*** sql*SELECT*     id,*     username,*     realname,*     PASSWORD,*     createDate,*     lastLoginTime,*     enabled,*     accountNonExpired,*     accountNonLocked,*     credentialsNonExpired* FROM*     sys_user* where*     username=#{username}*/UserModel user = userMapper.getUser(userName);if(user == null){return null;}//根据用户查询权限/*** sql* SELECT*       s6.id,*       s6.permName,*       s6.permTag,*       s6.url*   FROM*       ( SELECT s2.user_id FROM sys_user s1 LEFT JOIN sys_user_role s2 ON s1.id = s2.user_id WHERE s1.username = #{username} ) s4*       LEFT JOIN sys_role s3 ON s4.user_id = s3.id*       LEFT JOIN sys_role_permission s5 ON s5.role_id = s3.id*       LEFT JOIN sys_permission s6 ON s6.id = s5.perm_id*/List<PermissionModel> permissionList = permissionMapper.getPermission(user.getUsername());//创建权限集合List<GrantedAuthority> grantedAuthorities = new ArrayList<>();//添加权限permissionList.forEach(x ->{grantedAuthorities.add(new SimpleGrantedAuthority(x.getPermTag()));});//将权限绑定到useruser.setAuthorities(grantedAuthorities);return user;}
}
UserModel 这个地方要注意,这个User实体类实现了UserDetails重写了方法,那么这些方法默认是返回false,我们要改成true,不然登陆会出现失败的情况。还有一个问题,就是重写UserDetails的方法,刚好我们字段也有一个类似的字段,在启动的时候项目就检查到这个不符合规范,最后我也是将我实体类中的字段set get方法删除。
/*** 用户表*/
public class UserModel implements UserDetails {private Integer id;private String username;private String realname;private String password;private Date createDate;private Date lastLoginTime;private Integer enabled;private Integer accountNonExpired;private Integer accountNonLocked;private Integer credentialsNonExpired;//用户跟权限板顶,一对多private List<GrantedAuthority> authorities = new ArrayList<>();@Overridepublic List<GrantedAuthority> getAuthorities() {return authorities;}public void setAuthorities(List<GrantedAuthority> authorities) {this.authorities = authorities;}public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getUsername() {return username;}@Overridepublic boolean isAccountNonExpired() {return true;}@Overridepublic boolean isAccountNonLocked() {return true;}@Overridepublic boolean isCredentialsNonExpired() {return true;}@Overridepublic boolean isEnabled() {return true;}public void setUsername(String username) {this.username = username;}public String getRealname() {return realname;}public void setRealname(String realname) {this.realname = realname;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}public Date getCreateDate() {return createDate;}public void setCreateDate(Date createDate) {this.createDate = createDate;}public Date getLastLoginTime() {return lastLoginTime;}public void setLastLoginTime(Date lastLoginTime) {this.lastLoginTime = lastLoginTime;}}
MD5加密password
import java.security.MessageDigest;public class MD5Util {//盐private static final String SALT = "mayikt";public static String encode(String password) {password = password + SALT;MessageDigest md5 = null;try {md5 = MessageDigest.getInstance("MD5");} catch (Exception e) {throw new RuntimeException(e);}char[] charArray = password.toCharArray();byte[] byteArray = new byte[charArray.length];for (int i = 0; i < charArray.length; i++)byteArray[i] = (byte) charArray[i];byte[] md5Bytes = md5.digest(byteArray);StringBuffer hexValue = new StringBuffer();for (int i = 0; i < md5Bytes.length; i++) {int val = ((int) md5Bytes[i]) & 0xff;if (val < 16) {hexValue.append("0");}hexValue.append(Integer.toHexString(val));}return hexValue.toString();}
}
演示admin账户,全部权限。我只写了一个查询,其他省略了。



演示mykt-add,这个账户只有add权限,那么我们去用这个账户登陆去查询看看



最后我将代码上传到百度网盘

链接:https://pan.baidu.com/s/1ImSsNg1XdMlZEU922jEiKA
提取码:yyds

spring-security详解相关推荐

  1. Spring Security 详解

    0. 简介 ​ Spring Security 是 Spring家族中的一个安全管理框架.相比与另外一个安全框架Shiro,它提供了更丰富的功能,社区资源也比Shiro丰富. 一般来说中大型的项目都是 ...

  2. Spring Security 详解与实操第五节 JWT和Oauth2

    令牌扩展:如何使用 JWT 实现定制化 Token? 上一讲我们详细介绍了在微服务架构中如何使用 Token 对微服务的访问过程进行权限控制,这里的 Token 是类似"b7c2c7e0-0 ...

  3. Spring Security 详解与实操第一节 认证体系与密码安全

    开篇词 Spring Security,为你的应用安全与职业之路保驾护航 你好,我是鉴湘,拉勾教育专栏<Spring Cloud 原理与实战><Spring Boot 实战开发> ...

  4. spring security详解

    1.概要 Spring是非常流行和成功的Java应用开发框架,SpringSecurity正是Spring家族中的成员.SpringSecurity基于Spring框架,提供了一套Web应用安全性的完 ...

  5. 网上的一篇spring security详解教程,觉得不错,转过来了

    先来谈一谈Acegi的基础知识,Acegi的架构比较复杂,但是我希望我下面的只言片语能够把它说清楚.大家都知道,如果要对Web资源进行保护,最好的办法莫过于Filter,要想对方法调用进行保护,最好的 ...

  6. 《深入理解 Spring Cloud 与微服务构建》第十六章 Spring Boot Security 详解

    <深入理解 Spring Cloud 与微服务构建>第十六章 Spring Boot Security 详解 文章目录 <深入理解 Spring Cloud 与微服务构建>第十 ...

  7. Spring AOP详解(转载)所需要的包

    上一篇文章中,<Spring Aop详解(转载)>里的代码都可以运行,只是包比较多,中间缺少了几个相应的包,根据报错,几经百度搜索,终于补全了所有包. 截图如下: 在主测试类里面,有人怀疑 ...

  8. Spring JDBC详解

    <Spring JDBC详解> 本文旨在讲述Spring JDBC模块的用法.Spring JDBC模块是Spring框架的基础模块之一. 一.概述 在Spring JDBC模块中,所有的 ...

  9. Spring 体系结构详解

    Spring 体系结构详解 核心容器(Core Container) Core和Beans模块提供了Spring最基础的功能,提供IOC和依赖注入特性.这里的基础概念是BeanFactory,它提供对 ...

  10. [转载]Spring配置文件详解一:

    2019独角兽企业重金招聘Python工程师标准>>> 原文地址:Spring配置文件详解一:<context:annotation-config/>与<conte ...

最新文章

  1. codeforce A. Design Tutorial: Learn from Math
  2. 这个小学生毕业典礼被全世界围观:疫情之下开脑洞,《我的世界》还能这样玩!中国网友:作业写不完的我感到嫉妒...
  3. 基于NVIDIA显卡的硬编解码的一点心得 (完结)
  4. kylin如何支持flink_大数据集群运维(28) Kylin 配置使用 flink 构建 Cube
  5. 编程书籍阅读随谈(第四篇)
  6. 最实用的Git命令总结:新建本地分支、远程分支、关联和取消关联分支、清除本地和远程分支、合并分支、版本还原、tag命令、中文乱码解决方案、如何fork一个分支和修改后发起合并请求
  7. boost基础——any(二)
  8. shell学习之获取用户的输入命令read
  9. Eclipse tooltip变黑的修正
  10. java 正则表达式 unicode_java正则表达式中的POSIX 字符类和Unicode 块和类别的类介绍...
  11. 数学建模:层次分析法(AHP)详细步骤
  12. 基于springboot,vue旅游信息推荐系统
  13. pip install时timeout设置
  14. 支理解SVM的三层境界
  15. [js点滴(转)]JavaScript中的this陷阱的最全收集--没有之一
  16. java管理系统中期报告_基于Java的图书馆管理系统的设计-中期报告
  17. 获取对话框当前cfont_获取对话框当前cfont_MFC设置对话框、字体对话框、颜色对话框(转)...
  18. linux画平面图软件,画平面图最简单软件.docx
  19. 在 K8s 集群中创建 DERP 服务器
  20. 入坑KeePass(四)KeePass通过坚果云WebDav同步方法

热门文章

  1. 3个故事看穿了很多人
  2. 置换群---珠子染色
  3. 运动品牌推荐:双十一最值得买的运动用品推荐
  4. nginx配置动态ssl域名转发
  5. 区块链9999999666666
  6. HTML+css+js萤火虫动态按钮
  7. 神经网络解决哪些问题,神经网络结果不稳定
  8. 历史库存sap_SAP 取月度期初库存和月度期末库存(历史库存)
  9. C语言例题14:直接插入排序
  10. 小数加分数怎样计算讲解_11张图,搞定“小数与分数“计算技巧,这么全太有用啦!...