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

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. [CQOI2016]手机号码 数位DP
  2. Maven+eclipse快速入门
  3. 删除Autorun.inf的方法
  4. 【java设计模式】【行为模式Behavioral Pattern】迭代器模式Iterator Pattern
  5. 网关信息认证服务器不可达,网关消息认证服务器不可达
  6. SurfaceView + MediaPlayer 实现列表循环播放视频
  7. 天天模拟器显示获取服务器失败,天天模拟器FAQ、天天模拟器常见问题快速帮助...
  8. Unity3d——UGUI学习笔记
  9. 音视频技术开发周刊 | 177
  10. C语言用数组模拟实现栈(LIFO)
  11. 仿大逃杀源码_破咒不是您的典型大逃杀
  12. 【百问网】七天智能家居实战
  13. python药学应用_Python数据分析实例一:医院药品销售数据
  14. tortoiseGit管理的文件没有绿色红色等图标
  15. 普通人学python有什么用 ?学好了能干什么
  16. Go语言上手-基础语言
  17. String类的常见问题
  18. 基于ssm框架的毕业设计管理系统毕业设计源码211633
  19. 首发Cocos2d-x C++版仿《王者之剑》实现v1.0.1版
  20. C语言整型量包括哪些,C语言中的整型量

热门文章

  1. jpg图片损坏打不开怎么办?
  2. Python生成器、实现斐波那契数列
  3. 机器学习 - 编程练习(一):线性回归
  4. python 消息队列 get是从队首还是队尾取东西_Python -- queue队列模块
  5. Python 爬取 13966 条运维招聘信息,这些岗位最吃香!
  6. 《Java EE企业级应用开发教程(SSM)》练习题答案---第一章Spring的基本应用(仅供参考)
  7. CSU 1559 订外卖
  8. 教你自己搭建外卖分销小程序公众号-加入外卖分销,订外卖【美团】、【饿了么】
  9. 去美国考托福还是雅思?雅思更简单实用
  10. 必要商城和中国制造柔性生产