SpringBoot集成JWT 实现接口权限认证
JWT介绍
Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).该token被设计为紧凑且安全的, 特别适用于分布式站点的单点登录(`SSO`)场景。JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息, 以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,该token也可直接被用于认证,也可被加密。
优点
- 体积小、传输快
- 支持跨域授权,因为跨域无法共享cookie
- 分布式系统中,很好地解决了单点登录问题
缺点
因为JWT是无状态的,因此服务端无法控制已经生成的Token失效,是不可控的
使用场景
1. 认证,这是比较常见的使用场景,只要用户登录过一次系统,之后的请求都会包含签名出来的token,通过token也可以用来实现单点登录。
2. 交换信息,通过使用密钥对来安全的传送信息,可以知道发送者是谁、放置消息被篡改。
springboot集成JWT过程(注意: 使用了数据库, 先建表)
项目克隆 项目名称 springboot-jwt
地址: https://gitee.com/minili/springboot-demo.git
如果觉得该项目对你有帮助或者有疑问的话, 欢迎加星, 评论
添加表
一个是管理员表, 一个是存放token表
在项目下的db文件夹
SET FOREIGN_KEY_CHECKS=0; DROP TABLE IF EXISTS `manager`;
CREATE TABLE `manager` (
`managerId` int(5) unsigned NOT NULL AUTO_INCREMENT COMMENT '管理员id',
`managerName` varchar(50) NOT NULL,
`nickName` varchar(50) DEFAULT NULL,
`password` varchar(50) NOT NULL,
`managerLevelId` int(2) NOT NULL,
PRIMARY KEY (`managerId`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COMMENT='管理员表'; INSERT INTO `manager` VALUES ('', 'admin', 'admin', '4297f44b13955235245b2497399d7a93', '');
INSERT INTO `manager` VALUES ('', 'cscscs', 'cscscs', '4297f44b13955235245b2497399d7a93', ''); DROP TABLE IF EXISTS `managertoken`;
CREATE TABLE `managertoken` (
`managerId` int(20) NOT NULL,
`token` varchar(50) NOT NULL,
`expireTime` varchar(15) DEFAULT NULL COMMENT '过期时间yyyyMMddHHmmss',
`updateTime` varchar(15) DEFAULT NULL COMMENT '更新时间yyyyMMddHHmmss',
PRIMARY KEY (`managerId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
POM.XML
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.mycom</groupId>
<artifactId>funfast</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging> <name>funfast</name>
<description>project for Spring Boot JWT</description> <parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.1.RELEASE</version>
<relativePath/>
</parent> <properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<mysql-connector>5.1.38</mysql-connector>
<mybatis-plus-boot-starter.version>2.1.9</mybatis-plus-boot-starter.version>
<druid.version>1.1.10</druid.version>
<fastjson.version>1.2.39</fastjson.version>
<jwt.version>0.7.0</jwt.version>
</properties> <dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency> <!-- Spring Boot web依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- log4j2 依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
<!-- Spring Boot Test 依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency> <!-- Spring Boot JDBC 依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency> <!-- MySQL 连接驱动 依赖 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql-connector}</version>
</dependency>
<!-- druid 连接池 依赖 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>${druid.version}</version>
</dependency> <!-- shiro 权限控制 -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
</dependency> <!-- shiro ehcache (shiro缓存)-->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-ehcache</artifactId>
<version>1.4.0</version>
<exclusions>
<exclusion>
<artifactId>slf4j-api</artifactId>
<groupId>org.slf4j</groupId>
</exclusion>
</exclusions>
</dependency> <!-- jwt -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>${jwt.version}</version>
</dependency> <!-- fastjson 依赖 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency> </dependencies> <build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build> </project>
pom.xml
修改application.yml文件
# server
server:
tomcat:
uri-encoding: UTF-8
max-threads: 1000
min-spare-threads: 30
port: 8087
servlet:
context-path: / spring:
# 环境 dev|prod
profiles:
active: dev servlet:
multipart:
max-file-size: 100MB
max-request-size: 100MB
enabled: true datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.jdbc.Driver
druid:
url: jdbc:mysql://127.0.0.1:3306/fun-fast?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull
username: root
password: 123123 initial-size: 10
max-active: 100
min-idle: 10
max-wait: 60000
pool-prepared-statements: true
max-pool-prepared-statement-per-connection-size: 20
time-between-eviction-runs-millis: 60000
min-evictable-idle-time-millis: 300000
validation-query: SELECT 1
test-while-idle: true
test-on-borrow: true
test-on-return: false
stat-view-servlet:
enabled: true
url-pattern: /druid/*
login-username: admin
login-password: 123123
filter:
stat:
log-slow-sql: true
slow-sql-millis: 1000
merge-sql: false
wall:
config:
multi-statement-allow: true
application.yml
主体有5个文件需要添加,分别是shiroConfig、OAuth2Filer配置、OAuth2Realm、OAuth2Token、TokenGenerator
1. ShiroConfig配置
/**
* Shiro配置
*/
@Configuration
public class ShiroConfig { @Bean("sessionManager")
public SessionManager sessionManager(){
DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
sessionManager.setSessionValidationSchedulerEnabled(true);
sessionManager.setSessionIdCookieEnabled(true);
return sessionManager;
} @Bean("securityManager")
public SecurityManager securityManager(OAuth2Realm oAuth2Realm, SessionManager sessionManager) {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(oAuth2Realm);
securityManager.setSessionManager(sessionManager); return securityManager;
} @Bean("shiroFilter")
public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
shiroFilter.setSecurityManager(securityManager); //oauth过滤
Map<String, Filter> filters = new HashMap<>();
filters.put("oauth2", new OAuth2Filter());
shiroFilter.setFilters(filters); Map<String, String> filterMap = new LinkedHashMap<>();
filterMap.put("/druid/**", "anon");
filterMap.put("/app/**", "anon");
filterMap.put("/login", "anon");
filterMap.put("/**", "oauth2");
shiroFilter.setFilterChainDefinitionMap(filterMap); return shiroFilter;
} @Bean("lifecycleBeanPostProcessor")
public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
return new LifecycleBeanPostProcessor();
} @Bean
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator proxyCreator = new DefaultAdvisorAutoProxyCreator();
proxyCreator.setProxyTargetClass(true);
return proxyCreator;
} @Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
advisor.setSecurityManager(securityManager);
return advisor;
} }
2. OAuth2Filer配置
这个里面可以配置权限过滤的规则
/**
* oauth2过滤器
*/
public class OAuth2Filter extends AuthenticatingFilter { @Override
protected AuthenticationToken createToken(ServletRequest request, ServletResponse response) throws Exception {
//获取请求token
String token = getRequestToken((HttpServletRequest) request); if(StringUtil.isBlank(token)){
return null;
} return new OAuth2Token(token);
} @Override
protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
if(((HttpServletRequest) request).getMethod().equals(RequestMethod.OPTIONS.name())){
return true;
} return false;
} @Override
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
//获取请求token,如果token不存在,直接返回401
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
String token = getRequestToken((HttpServletRequest) request);
if(StringUtil.isBlank(token)){
HttpServletResponse httpResponse = (HttpServletResponse) response;
httpResponse.setHeader("Access-Control-Allow-Credentials", "true");
httpResponse.setHeader("Access-Control-Allow-Origin", httpServletRequest.getHeader("Origin")); JSONObject json = new JSONObject();
json.put("code", "401");
json.put("msg", "invalid token"); httpResponse.getWriter().print(json); return false;
} return executeLogin(request, response);
} @Override
protected boolean onLoginFailure(AuthenticationToken token, AuthenticationException e, ServletRequest request, ServletResponse response) {
HttpServletResponse httpResponse = (HttpServletResponse) response;
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
httpResponse.setContentType("application/json;charset=utf-8");
httpResponse.setHeader("Access-Control-Allow-Credentials", "true");
httpResponse.setHeader("Access-Control-Allow-Origin", httpServletRequest.getHeader("Origin"));
try {
//处理登录失败的异常
Throwable throwable = e.getCause() == null ? e : e.getCause(); JSONObject json = new JSONObject();
json.put("code", "401");
json.put("msg", throwable.getMessage()); httpResponse.getWriter().print(json);
} catch (IOException e1) { } return false;
} /**
* 获取请求的token
*/
private String getRequestToken(HttpServletRequest httpRequest){
//从header中获取token
String token = httpRequest.getHeader("token"); //如果header中不存在token,则从参数中获取token
if(StringUtil.isBlank(token)){
token = httpRequest.getParameter("token");
} return token;
}
}
OAuth2Filer
3. OAuth2Realm配置
这个里面可以设置角色、权限和认证信息
/**
* 认证
*/
@Component
public class OAuth2Realm extends AuthorizingRealm {
@Autowired
private ManagerService managerService; @Override
public boolean supports(AuthenticationToken token) {
return token instanceof OAuth2Token;
} /**
* 授权(验证权限时调用, 控制role 和 permissins时使用)
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
ManagerInfo manager = (ManagerInfo)principals.getPrimaryPrincipal();
Integer managerId = manager.getManagerId(); SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); // 模拟权限和角色
Set<String> permsSet = new HashSet<>();
Set<String> roles = new HashSet<>();
if (managerId == 1) {
// 超级管理员-权限
permsSet.add("delete");
permsSet.add("update");
permsSet.add("view"); roles.add("admin");
} else {
// 普通管理员-权限
permsSet.add("view"); roles.add("test");
} info.setStringPermissions(permsSet);
info.setRoles(roles); return info;
} /**
* 认证(登录时调用)
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
String accessToken = (String) token.getPrincipal(); //根据accessToken,查询用户信息
ManagerToken managerToken = managerService.queryByToken(accessToken);
//token失效
SimpleDateFormat sm = new SimpleDateFormat("yyyyMMddHHmmss");
Date expireTime;
boolean flag = true;
try {
expireTime = sm.parse(managerToken.getExpireTime());
flag = managerToken == null || expireTime.getTime() < System.currentTimeMillis();
} catch (ParseException e) {
e.printStackTrace();
} if(flag){
throw new IncorrectCredentialsException("token失效,请重新登录");
} //查询用户信息
ManagerInfo managerInfo = managerService.getManagerInfo(managerToken.managerId);
//账号锁定
// if(managerInfo.getStatus() == 0){
// throw new LockedAccountException("账号已被锁定,请联系管理员");
// } SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(managerInfo, accessToken, getName()); return info;
}
}
OAuth2Realm
4. OAuth2Token设置
/**
* token
*/
public class OAuth2Token implements AuthenticationToken {
private String token; public OAuth2Token(String token){
this.token = token;
} @Override
public String getPrincipal() {
return token;
} @Override
public Object getCredentials() {
return token;
}
}
5. TokenGenerator, 生成token
/**
* 生成token
*/
public class TokenGenerator { public static String generateValue() {
return generateValue(UUID.randomUUID().toString());
} private static final char[] hexCode = "0123456789abcdef".toCharArray(); public static String toHexString(byte[] data) {
if (data == null) {
return null;
}
StringBuilder r = new StringBuilder(data.length * 2);
for (byte b : data) {
r.append(hexCode[(b >> 4) & 0xF]);
r.append(hexCode[(b & 0xF)]);
}
return r.toString();
} public static String generateValue(String param) {
try {
MessageDigest algorithm = MessageDigest.getInstance("MD5");
algorithm.reset();
algorithm.update(param.getBytes());
byte[] messageDigest = algorithm.digest();
return toHexString(messageDigest);
} catch (Exception e) {
throw new RuntimeException("生成Token失败", e);
}
}
}
Controller
@RestController
public class WebController { private static final Logger LOGGER = LogManager.getLogger(WebController.class); @Autowired
private ManagerService managerService; @RequestMapping("/login")
public JSONObject login(@RequestParam("username") String username,
@RequestParam("password") String password) {
JSONObject json = new JSONObject();
json.put("result", false);
json.put("msg", "账号或密码不正确"); // 用户信息
ManagerInfo managerInfo = managerService.getManagerInfo(username);
// 账号不存在、密码错误
if (managerInfo == null || !managerInfo.getPassword().equals(password)) {
return json;
} ManagerToken managerToken = managerService.saveToken(managerInfo.managerId);
json.put("token", managerToken.token);
json.put("result", true);
json.put("msg", "登陆成功"); return json;
} /**
* 必须带token请求, 否则返回401
*/
@GetMapping("/article")
public BaseResponse article() {
return new BaseResponse(true, "article: You are already logged in", null);
} /**
* 不必带token也能请求到内容, 因为在shiro中配置了过滤规则
*/
@GetMapping("/app/article")
public BaseResponse appArticle() {
return new BaseResponse(true, "appArticle: You are already logged in", null);
} /**
* 需要是超级管理员的token才能查看,
*/
@GetMapping("/require_role")
@RequiresRoles("admin")
public BaseResponse requireRole() {
return new BaseResponse(true, "You are visiting require_role", null);
} /**
* 需要有update权限才能访问
*/
@GetMapping("/require_permission")
// @RequiresPermissions(logical = Logical.AND, value = {"view", "edit"})
@RequiresPermissions(logical = Logical.AND, value = {"update"})
public BaseResponse requirePermission() {
return new BaseResponse(true, "You are visiting permission require update", null);
} }
Service
@Service
public class ManagerService extends AbstractService {
//12小时后过期
private final static int EXPIRE = 3600 * 12 * 1000; public ManagerInfo getManagerInfo(String managerName) {
String sql = "select a.managerName, a.managerLevelId,a.managerId, a.password"
+ " from manager a where a.managerName=?";
ManagerInfo manager = jdbcDao.queryForObject(sql, new Object[] { managerName }, ManagerInfo.class); return manager;
} public ManagerToken saveToken(Integer managerId) {
ManagerToken managerToken = new ManagerToken();
managerToken.managerId = managerId; //生成一个token
managerToken.token = TokenGenerator.generateValue();
//过期时间
Date expireTime = new Date(System.currentTimeMillis() + EXPIRE); // 更新时间/过期时间
SimpleDateFormat sm = new SimpleDateFormat("yyyyMMddHHmmss");
Date systemDate = new Date();
managerToken.updateTime = sm.format(systemDate);
managerToken.expireTime = sm.format(expireTime); String sql = "insert into managertoken (managerId, token, updateTime, expireTime) values (?,?,?,?)"
+ " ON DUPLICATE KEY UPDATE token=?, updateTime=?, expireTime=?";
jdbcDao.update(sql, new Object[]{managerToken.managerId, managerToken.token, managerToken.updateTime,
managerToken.expireTime, managerToken.token, managerToken.updateTime, managerToken.expireTime}); return managerToken;
} @Transactional(propagation= Propagation.REQUIRED, isolation= Isolation.DEFAULT, readOnly = true, rollbackFor = Exception.class)
public ManagerInfo getManagerInfo(Integer managerId) {
if (managerId == null) {
return null;
} String sql = "select a.managerId, a.managerName, a.managerLevelId from manager a " +
"where a.managerId=?";
ManagerInfo manager = jdbcDao.queryForObject(sql, new Object[]{managerId}, ManagerInfo.class); return manager;
} public ManagerToken queryByToken(String token) {
if (token == null || "".equals(token)) {
return null;
} String sql = "select managerid managerId, token, expireTime, updateTime from managertoken where token=?";
ManagerToken managerToken = jdbcDao.queryForObject(sql, new Object[]{token}, ManagerToken.class); return managerToken;
} }
service
这里省略了一些基础的实体类、工具类,详见代码
登陆测试
先登陆获取到token(localhost:8087/login?username=cscscs&password=4297f44b13955235245b2497399d7a93)
这里测试的用户有两个一个admin(超级管理员), 一个是cscscs
测试需要认证的接口
1.不带token访问
2.带token访问
注意是headers中添加参数token
测试不需要认证的接口
在OAuth2Filter中我对,/app 路径下的接口不需要认证
测试角色认证的接口
/require_role, 这个接口需要admin角色才能访问,在OAuth2Realm中我设置了admin用户为超级管理员角色, cscscs用户为test角色
1. cscscs用户访问(选择cscscs用户的token)
2.admin用户访问(选择admin用户的token)
测试权限认证的接口
平时我们可以设置管理员是否有删除,更新记录的权限
/require_permission在控制器中设置了只有拥有update权限的用户才能访问, 在OAuth2Realm中我给了admin用户update的权限, 给了cscscs用户view的权限
1.使用cscscs用户的token访问
2. 使用admin用户访问
结语
1. 希望能给自己帮助、也给别人帮助,有任何疑问或者意见,在下方留言哦
2, 有很多不足可以改进, 如缓存啊, 更准确的权限设置啊, 但他可以帮你构建一个完整可用的JWT
之前看了网上的例子, 理论很好, 例子却没跑通, aaaaa,,,
SpringBoot集成JWT 实现接口权限认证的更多相关文章
- SpringBoot系列 - 集成JWT实现接口权限认证
会飞的污熊 2018-01-22 16173 阅读 spring jwt springboot RESTful API认证方式 一般来讲,对于RESTful API都会有认证(Authenticati ...
- 轻松上手SpringBoot+SpringSecurity+JWT实RESTfulAPI权限控制实战
前言 我们知道在项目开发中,后台开发权限认证是非常重要的,springboot 中常用熟悉的权限认证框架有,shiro,还有就是springboot 全家桶的 security当然他们各有各的好处,但 ...
- 基于Springboot集成security、oauth2实现认证鉴权、资源管理
1.Oauth2简介 OAuth(开放授权)是一个开放标准,允许用户授权第三方移动应用访问他们存储在另外的服务提供者上的信息,而不需要将用户名和密码提供给第三方移动应用或分享他们数据的所有内容,OAu ...
- springboot动态修改日志级别+权限认证
1. springboot动态修改日志级别+权限认证 1.1. 需求 网上找到的动态修改日志级别的方式,基本都是没有权限验证的,或者特地关闭权限验证,但也没给出加上验证的解决方式 修改日志等级也是一个 ...
- SpringBoot集成JWT实现权限认证
目录 一.JWT认证流程 二.SpringBoot整合JWT 三.测试 上一篇文章<一分钟带你了解JWT认证!>介绍了JWT的组成和认证原理,本文将介绍下SpringBoot整合JWT实现 ...
- SpringBoot集成JWT实现token验证
原文:https://www.jianshu.com/p/e88d3f8151db JWT官网: https://jwt.io/ JWT(Java版)的github地址:https://github. ...
- SpringBoot集成JWT
JWT(json web tokens)是目前比较流行的跨域认证解决方案:说通俗点就是比较流行的token生成和校验的方案.碰巧公司有个app的项目的token采用了jwt方案,因此记录下后端 ...
- JWT实现用户权限认证
网上的java基础教程曾教会我们,将用户登录信息存在session(服务器端)中,需要验证的时候拿出来作对比以达到身份 验证的效果.但这种方式暴露的问题也是可想而知的: 1.Seesion:每次认证用 ...
- Springboot集成swagger2生成接口文档
[转载请注明]: 原文出处:https://www.cnblogs.com/jstarseven/p/11509884.html 作者:jstarseven 码字挺辛苦的..... 一 ...
随机推荐
- 以太坊系列之七: p2p模块的dial--以太坊源码学习
dial.go阅读手记 dial.go是负责和peer建立连接关系的地方,主要是实现 type dialer interface { /* peers已经有的结点 */ newTasks(runnin ...
- 教你如何选择BI数据可视化工具
本文来自网易云社区. 关于如何选择BI数据可视化工具,总体而言,主流BI产品在选择的时候要除了需要考虑从数据到展现.从公司内到公司外等各种场景,结合前面朋友的回答,还需要考虑以下几点:1:以后的数据处 ...
- Mybatis注解开发
mybatis 的常用注解: @Insert:实现新增 @Update:实现更新 @Delete:实现删除 @Select:实现查询 @Result:实现结果集封装 @Results:可以与 @Res ...
- 【bzoj1014】: [JSOI2008]火星人prefix 平衡树-字符串-hash-二分
[bzoj1014]: [JSOI2008]火星人 用平衡树维护字符串的hash 然后询问的时候二分一下就好了 /* http://www.cnblogs.com/karl07/ */ #includ ...
- ASPxGridView后台实现隐藏新增按钮
(ASPxGridView2.Columns[0] as GridViewCommandColumn).NewButton.Visible = false;//0应该代表的是NewButton所在的列 ...
- PS基本操作汇总(持续更新)
一.放大缩小图片:ctrl+/- 二.缩小gif:ps时打开后,web格式保存,里面点出优化面板,选gif格式,颜色数减小,如128,损耗30,图片大小也可调整,比如调整为50%,点击预览,可在浏览器 ...
- 基于openstack搭建百万级并发负载均衡器的解决方案
最近,喜欢研究一些国外技术大咖们的文章,而这篇文章是基于openstack负载均衡器的解决方案,做的一些总结~希望能够给小伙伴带来一些灵感或者帮助. openstack现有的负载均衡解决方案,无论是l ...
- I/O(输入/输出)---File类
File:表示文件与目录.用它来对文件或目录进行基本操作,它可以查出文件的基本相关信息,比如:名称.最后的修改日期.文件大小. 使用File类操作文件和目录属性步骤: 1.引入File类 import ...
- hexo博客的相关配置
获得更多资料欢迎进入我的网站或者 csdn或者博客园 前面两节讲解了hexo博客的搭建以及jacman主题的配置,这节主要讲解博客的一些相关配置.比如404页面,图床,自定义页面,个人网站绑定(重要的 ...
- 【hadoop】 eclipse中的“run on hadoop”和打包成jar提交任务的区别
eclipse中的 调试运行 及 “run on hadoop”默认只是运行在单机上的,因为要想在集群中让程序分布式运行还要经历上传类文件.分发到各个节点等过程, 一个简单的“run on hadoo ...