文档章节

apache-shiro 学习笔记

maskleo
 maskleo
发布于 2015/10/18 19:59
字数 1740
阅读 51
收藏 0
点赞 0
评论 0
(一) 看到SpringSide4居然也用shiro作为安全框架,不是用的spring-security。着实有点惊讶。
apache-shiro的强大可见一斑。

(二) apache-shiro依赖的包
<dependency>
	<groupId>org.apache.shiro</groupId>
	<artifactId>shiro-core</artifactId>
	<version>1.2.1</version>
</dependency>
<dependency>
	<groupId>org.apache.shiro</groupId>
	<artifactId>shiro-web</artifactId>
	<version>1.2.1</version>
</dependency>
<dependency>
	<groupId>org.apache.shiro</groupId>
	<artifactId>shiro-ehcache</artifactId>
	<version>1.2.1</version>
</dependency>
<dependency>
	<groupId>org.apache.shiro</groupId>
	<artifactId>shiro-spring</artifactId>
	<version>1.2.1</version>
</dependency>

除此之外还有一些东西也不可少spring, spring-mvc, ibatis等
  • spring.3.1.2
  • spring-mvc.3.1.2
  • ibatis.2.3.4
  • cglib.2.2


(三) demo采取比较典型的“User-Role-Permission”模型
-- -----------------------------------------------------
-- Table `shiro`.`TBL_PERMISSION`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `shiro`.`TBL_PERMISSION` ;

CREATE  TABLE IF NOT EXISTS `shiro`.`TBL_PERMISSION` (
  `PERMISSION_ID` INT NOT NULL AUTO_INCREMENT ,
  `PERMISSION_NAME` VARCHAR(45) NULL ,
  PRIMARY KEY (`PERMISSION_ID`) ,
  UNIQUE INDEX `PERMISSION_NAME_UNIQUE` (`PERMISSION_NAME` ASC) )
ENGINE = InnoDB;

-- -----------------------------------------------------
-- Table `shiro`.`TBL_ROLE`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `shiro`.`TBL_ROLE` ;

CREATE  TABLE IF NOT EXISTS `shiro`.`TBL_ROLE` (
  `ROLE_ID` INT NOT NULL AUTO_INCREMENT ,
  `ROLE_NAME` VARCHAR(45) NULL ,
  PRIMARY KEY (`ROLE_ID`) ,
  UNIQUE INDEX `ROLE_NAME_UNIQUE` (`ROLE_NAME` ASC) )
ENGINE = InnoDB;

-- -----------------------------------------------------
-- Table `shiro`.`TBL_USER`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `shiro`.`TBL_USER` ;

CREATE  TABLE IF NOT EXISTS `shiro`.`TBL_USER` (
  `USER_ID` INT NOT NULL AUTO_INCREMENT ,
  `USER_USERNAME` VARCHAR(45) NOT NULL ,
  `USER_PASSWORD` CHAR(32) NOT NULL ,
  PRIMARY KEY (`USER_ID`) ,
  UNIQUE INDEX `USER_USERNAME_UNIQUE` (`USER_USERNAME` ASC) )
ENGINE = InnoDB;

-- -----------------------------------------------------
-- Table `shiro`.`TBL_PERMISSION_ROLE`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `shiro`.`TBL_PERMISSION_ROLE` ;

CREATE  TABLE IF NOT EXISTS `shiro`.`TBL_PERMISSION_ROLE` (
  `ROLE_ID` INT NOT NULL ,
  `PERMISSION_ID` INT NOT NULL ,
  PRIMARY KEY (`ROLE_ID`, `PERMISSION_ID`) )
ENGINE = InnoDB;

-- -----------------------------------------------------
-- Table `shiro`.`TBL_ROLE_USER`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `shiro`.`TBL_ROLE_USER` ;

CREATE  TABLE IF NOT EXISTS `shiro`.`TBL_ROLE_USER` (
  `ROLE_ID` INT NOT NULL ,
  `USER_ID` INT NOT NULL ,
  PRIMARY KEY (`ROLE_ID`, `USER_ID`) )
ENGINE = InnoDB;


自己实现一个UserDao, ibatis实现。
这个不是本文要记述的重点,简单贴一下代码。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sqlMap PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN" "http://ibatis.apache.org/dtd/sql-map-2.dtd">
<sqlMap namespace="user">

	<typeAlias alias="User" type="com.ztgame.sd.domain.User"/>

	<resultMap class="User" id="result-map-01" groupBy="id">
		<result property="id" column="USER_ID" />
		<result property="username" column="USER_USERNAME" />
		<result property="password" column="USER_PASSWORD" />
		<result property="roleSet" resultMap="role.result-map-01" />
	</resultMap>
	
	<!-- +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->

	<sql id="select-base-01">
		SELECT 
			u.USER_ID,
			u.USER_USERNAME,
			u.USER_PASSWORD,
			r.ROLE_ID,
			r.ROLE_NAME,
			p.PERMISSION_ID,
			p.PERMISSION_NAME
		FROM
		  tbl_user as u,
		  tbl_role as r,
		  tbl_permission as p,
		  tbl_permission_role as pr,
		  tbl_role_user as ru
		WHERE
		  u.USER_ID = ru.USER_ID
		AND
		  r.ROLE_ID = ru.ROLE_ID
		AND
		  p.PERMISSION_ID = pr.PERMISSION_ID
		AND
		  r.ROLE_ID = pr.ROLE_ID
	</sql>
	
	<!-- +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
	
	<select id="select-01" parameterClass="string" resultMap="result-map-01">
		<include refid="select-base-01" />
		AND
			u.USER_USERNAME = #username#
	</select>

</sqlMap>

public interface UserDao {

	User findUserByUsername(String username);

}

@Repository("userDao")
public class UserDaoImpl implements UserDao {

	@Resource
	private SqlMapClientTemplate sqlMapClientTemplate;
	
	@Override
	public User findUserByUsername(String username) {
		Validate.notEmpty(username, "用户名不可为null或empty string");
		return (User) sqlMapClientTemplate.queryForObject("user.select-01", username);
	}

}


(三) 用户和权限数据源是自己设计的,应该实现自己的Realm对象。
package com.ztgame.sd.security.realm;

import java.util.HashSet;
import java.util.Set;

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;

import com.ztgame.sd.dao.UserDao;
import com.ztgame.sd.domain.Permission;
import com.ztgame.sd.domain.Role;
import com.ztgame.sd.domain.User;

public class JdbcRealm extends AuthorizingRealm 
	implements
			Realm, 
			InitializingBean
{

	private UserDao userDao;

	// ------------------------------------------------------------------------------------------------------------

	@Override
	public void afterPropertiesSet() throws Exception {
		Assert.notNull(userDao);
	}

	// ------------------------------------------------------------------------------------------------------------

	@Override
	public String getName() {
		return getClass().getName();
	}

	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
		
		String username = (String) super.getAvailablePrincipal(principals);
		User user = userDao.findUserByUsername(username);
		
		SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
		Set<String> roles = new HashSet<String>();
		Set<String> permissions = new HashSet<String>();

		for (Role role : user.getRoleSet()) {
			roles.add(role.getName());
			for (Permission per : role.getPermissionSet()) {
				permissions.add(per.getName());
			}
		}

		info.addRoles(roles);
		info.addStringPermissions(permissions);

		return info;
	}

	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(
			AuthenticationToken token) throws AuthenticationException {

		SimpleAuthenticationInfo info = null;

		UsernamePasswordToken upt = (UsernamePasswordToken) token;
		String username = upt.getUsername();
		User user = userDao.findUserByUsername(username);
		
		if (user == null) {
			throw new AuthenticationException();
		}

		info = new SimpleAuthenticationInfo(user.getUsername(), user.getPassword(), getName());

		return info;
	}

	// ------------------------------------------------------------------------------------------------------------

	public void setUserDao(UserDao userDao) {
		this.userDao = userDao;
	}

}


(四) apache-shiro的配置
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
	
	<!-- apache-shiro 核心拦截器 -->
	<filter>
		<filter-name>shiroFilter</filter-name>
		<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
	</filter>
	<filter-mapping>
		<filter-name>shiroFilter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>

	<!-- 其他无关apache-shiro -->

</web-app>


spring-shiro.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
	xmlns:c="http://www.springframework.org/schema/c" xmlns:util="http://www.springframework.org/schema/util"
	xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
		http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.1.xsd
		http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd">
		
	<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>

	<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
		<property name="securityManager" ref="securityManager" />
		<property name="loginUrl" value="/login" />
		<property name="successUrl" value="/login/loginSuccessFull" />
		<property name="unauthorizedUrl" value="/login/unauthorized" />
		<!--
		<property name="filterChainDefinitions">
			<value>
				/ = anon
			</value>
		</property>
		-->
	</bean>

	<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
		<property name="authenticator" ref="authenticator" />
		<property name="sessionManager" ref="sessionManager" />
		<property name="cacheManager" ref="cacheManager" />
		<property name="realms">
			<list>
				<bean class="com.ztgame.sd.security.realm.JdbcRealm">
					<property name="userDao" ref="userDao" />
					<property name="credentialsMatcher" ref="hashedCredentialsMatcher" />
				</bean>
			</list>
		</property>
	</bean>

	<bean id="authenticator" class="org.apache.shiro.authc.pam.ModularRealmAuthenticator" />	

	<bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
		<property name="sessionDAO" ref="sessionDAO" />
	</bean>

	<bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager" />

	<bean id="sessionDAO" class="org.apache.shiro.session.mgt.eis.MemorySessionDAO" />

	<bean id="hashedCredentialsMatcher" class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
		<property name="hashAlgorithmName" value="MD5" />
		<property name="storedCredentialsHexEncoded" value="true" />
		<property name="hashIterations" value="1" />
	</bean>
</beans>


spring-mvc.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
	xmlns:c="http://www.springframework.org/schema/c" xmlns:util="http://www.springframework.org/schema/util"
	xmlns:aop="http://www.springframework.org/schema/aop" xmlns:mvc="http://www.springframework.org/schema/mvc"
	xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
		http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.1.xsd
		http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
		http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd
		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd">

	<!-- 其他spring-mvc框架配置 -->

	<!-- 
		以下两个bean的配置是为了在Controller层使用元注释控制权限
		如果使用spring-mvc一定要不要放在webroot的配置文件中
	 -->
	<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor" />

	<bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
		<property name="securityManager" ref="securityManager" />
	</bean>

</beans>


(五) jsp-taglib 支持
  • <shiro:authenticated> 登录之后
  • <shiro:notAuthenticated> 不在登录状态时
  • <shiro:guest> 用户在没有RememberMe时
  • <shiro:user> 用户在RememberMe时
  • <shiro:hasAnyRoles name="abc,123" > 在有abc或者123角色时
  • <shiro:hasRole name="abc"> 拥有角色abc
  • <shiro:lacksRole name="abc"> 没有角色abc
  • <shiro:hasPermission name="abc"> 拥有权限abc
  • <shiro:lacksPermission name="abc"> 没有权限abc
  • <shiro:principal> 显示用户登录名

[官方文档] http://shiro.apache.org/web.html#Web-taglibrary

(六) 默认过滤器(10个)
  • anon -- org.apache.shiro.web.filter.authc.AnonymousFilter
  • authc -- org.apache.shiro.web.filter.authc.FormAuthenticationFilter
  • authcBasic -- org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter
  • perms -- org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter
  • port -- org.apache.shiro.web.filter.authz.PortFilter
  • rest -- org.apache.shiro.web.filter.authz.HttpMethodPermissionFilter
  • roles -- org.apache.shiro.web.filter.authz.RolesAuthorizationFilter
  • ssl -- org.apache.shiro.web.filter.authz.SslFilter
  • user -- org.apache.shiro.web.filter.authc.UserFilter
  • logout -- org.apache.shiro.web.filter.authc.LogoutFilter


anon:例子/admins/**=anon 没有参数,表示可以匿名使用。
authc:例如/admins/user/**=authc表示需要认证(登录)才能使用,没有参数
roles:例子/admins/user/**=roles[admin],参数可以写多个,多个时必须加上引号,并且参数之间用逗号分割,当有多个参数时,例如admins/user/**=roles["admin,guest"],每个参数通过才算通过,相当于hasAllRoles()方法。
perms:例子/admins/user/**=perms[user:add:*],参数可以写多个,多个时必须加上引号,并且参数之间用逗号分割,例如/admins/user/**=perms["user:add:*,user:modify:*"],当有多个参数时必须每个参数都通过才通过,想当于isPermitedAll()方法。
rest:例子/admins/user/**=rest[user],根据请求的方法,相当于/admins/user/**=perms[user:method] ,其中method为post,get,delete等。
port:例子/admins/user/**=port[8081],当请求的url的端口不是8081是跳转到schemal://serverName:8081?queryString,其中schmal是协议http或https等,serverName是你访问的host,8081是url配置里port的端口,queryString是你访问的url里的?后面的参数。
authcBasic:例如/admins/user/**=authcBasic没有参数表示httpBasic认证
ssl:例子/admins/user/**=ssl没有参数,表示安全的url请求,协议为https
user:例如/admins/user/**=user没有参数表示必须存在用户,当登入操作时不做检查
[官方文档] http://shiro.apache.org/web.html#Web-FilterChainDefinitions

(七) 常用元注释
  • @RequiresAuthentication 验证用户是否登录,等同于方法subject.isAuthenticated() 结果为true时
  • @RequiresUser 验证用户是否被记忆,user有两种含义:一种是成功登录的(subject.isAuthenticated()结果为true)另外一种是被记忆的(subject.isRemembered()结果为true)
  • @RequiresGuest 验证是否为匿名请求
  • @RequiresRoles 必须要有角色
  • @RequiresPermissions 必须要有权限

© 著作权归作者所有

共有 人打赏支持
maskleo
粉丝 14
博文 107
码字总数 17344
作品 0
深圳
程序员
Spring+Shiro+CAS整合配置笔记

一、前言 Apache Shiro与Spring Security一样是Java的一个安全框架。那为什么与Spring整合却用Shiro?不要问为什么,任性!开个玩笑:D 其实我个人是认为Spring Security太过于笨重,要写太多...

qllinhongyu ⋅ 2014/12/09 ⋅ 0

Shrio学习笔记(一)

Shiro(发音shee-roh)是什么:apache的一个Java安全框架,由2003年开始的"JSecurity"项目发展而来,比Spring Security简单些。 Shiro官网:http://shiro.apache.org/ Shiro能干什么:帮助我...

lzg14 ⋅ 2014/05/30 ⋅ 1

【Shiro】Shiro从小白到大神(一)-Shiro入门

本系列是我在学习Shiro的路上的笔记,第一篇是属于非常入门级别的。 首先是介绍了下shiro,然后进行了一个小例子进行实际的操作 本节操作不涉及数据库,只是文本字符操作认证 Shiro简介: 百度...

qq_26525215 ⋅ 2017/09/22 ⋅ 0

Shiro学习笔记入门--Hello Shiro

Apache Shiro是Apache的一个安全框架.对比Spring Security,可能没有Spring Security功能多,但是在实际并不需要那么重的东西.shiro简小精悍.大多项目绰绰有余.(JBOSS好像也有个什么安全框架....

浮躁的码农 ⋅ 2015/12/01 ⋅ 0

Apache Shiro学习笔记(一)

一、在web环境下使用Shiro使用 将 Shiro 集成到任何 Web 应用程序的最简单的方法是在 web.xml 中配置 ContextListener 和 Filter,理解如何读取 Shiro 的 INI 配置文件。 1、web.xml配置 <!...

有资本再款 ⋅ 2015/11/16 ⋅ 0

Shiro权限管理笔记

一.用户身份认证 身份认证,就是判断一个用户是否为合法用户的处理过程。最常用的简单身份认证方式是系统通过核对用户输入的用户名和口令,看其是否与系统中存储的该用户的用户名和口令一致,...

Mr_欢先生 ⋅ 2017/11/28 ⋅ 0

关于开源权限框架Shiro的笔记(一)

Shiro的官方文档的URL是:http://shiro.apache.org/reference.html。引入如下依赖: <!-- junit --><dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.10</v......

DENGJM ⋅ 2015/09/28 ⋅ 0

Apache Shiro 使用手册

很好的学习资源,谢谢kdboy博主! Apache Shiro 使用手册(一)Shiro架构介绍 http://kdboy.iteye.com/blog/1154644 Apache Shiro 使用手册(二)Shiro架构介绍 http://kdboy.iteye.com/blo...

dmrs ⋅ 2015/10/18 ⋅ 0

spring +quartz maven配置

quartz做定时任务,之前使用过,但是当时没有做笔记,导致又折腾了一点时间由于使用的是spring+hibernate的项目,使用maven管理包maven配置如下: work0 0 0/12 ? class="org.springframewor...

zph-alan ⋅ 2016/09/22 ⋅ 0

cas与shiro整合笔记

遇见问题备足: <!-- Shiro Filter --> <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> <property name="securityManager" ref="securityManager" />......

云在天 ⋅ 2013/04/15 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

聊聊spring cloud的RequestRateLimiterGatewayFilter

序 本文主要研究一下spring cloud的RequestRateLimiterGatewayFilter GatewayAutoConfiguration @Configuration@ConditionalOnProperty(name = "spring.cloud.gateway.enabled", matchIfMi......

go4it ⋅ 34分钟前 ⋅ 0

Spring JavaConfig 注解

JavaConfig注解允许开发者将Bean的定义和配置放在Java类中。它是除使用XML文件定义和配置Bean外的另一种方案。 配置: 如一个Bean如果在XML文件可以这样配置: <bean id="helloBean" class="...

霍淇滨 ⋅ 41分钟前 ⋅ 0

Spring clound 组件

Spring Cloud技术应用从场景上可以分为两大类:润物无声类和独挑大梁类。 润物无声,融合在每个微服务中、依赖其它组件并为其提供服务。 Ribbon,客户端负载均衡,特性有区域亲和、重试机制。...

英雄有梦没死就别停 ⋅ 43分钟前 ⋅ 0

Confluence 6 重新获得站点备份文件

Confluence 将会创建备份,同时压缩 XML 文件后存储熬你的 <home-directory>/backups> 目录中。你需要自己访问你安装的 Confluence 服务器,并且从服务器上获得这个文件。 运行从 Confluence...

honeymose ⋅ 47分钟前 ⋅ 0

informix的常用SQL语句

1、创建数据库 eg1. 创建不记录日志的库testdb,参考语句如下: CREATE DATABASE testdb; eg2. 创建带缓冲式的记录日志的数据库testdb(SQL语句不一定在事务之中,拥有者名字不被用于对象的解...

wangxuwei ⋅ 今天 ⋅ 0

matplotlib画图

最简单的入门是从类 MATLAB API 开始,它被设计成兼容 MATLAB 绘图函数。 from pylab import *from numpy import *x = linspace(0, 5, 10)y = x ** 2figure()plot(x, y, 'r')...

Dr_hu ⋅ 今天 ⋅ 0

RabbitMQ学习以及与Spring的集成(三)

本文介绍RabbitMQ与Spring的简单集成以及消息的发送和接收。 在RabbitMQ的Spring配置文件中,首先需要增加命名空间。 xmlns:rabbit="http://www.springframework.org/schema/rabbit" 其次是模...

onedotdot ⋅ 今天 ⋅ 0

JAVA实现仿微信红包分配规则

最近过年发红包拜年成为一种新的潮流,作为程序猿对算法的好奇远远要大于对红包的好奇,这里介绍一种自己想到的一种随机红包分配策略,还请大家多多指教。 算法介绍 一、红包金额限制 对于微...

小致dad ⋅ 今天 ⋅ 0

Python 数电表格格式化 xlutils xlwt xlrd的使用

需要安装 xlutils xlwt xlrd 格式化前 格式化后 代码 先copy读取的表格,然后按照一定的规则修改,将昵称中的学号提取出来替换昵称即可 from xlrd import open_workbookfrom xlutils.copy ...

阿豪boy ⋅ 今天 ⋅ 0

面试题:使用rand5()生成rand7()

前言 读研究生这3 年,思维与本科相比变化挺大的,这几年除了看论文、设计方案,更重要的是学会注重先思考、再实现,感觉更加成熟吧,不再像个小P孩,人年轻时总会心高气傲。有1 道面试题:给...

初雪之音 ⋅ 今天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部