剑指Offer22
从上往下打印出二叉树的每个节点,同层节点从左至右打印。
思路:定义一个链表和一个数组,链表用来存放二叉树的节点,数组用来存放打印的结果,先将根节点放入链表,然后将其弹出,并放入数组中,如果弹出的节点左子节点不为空,将左子节点放入链表中,如果弹出的节点右子节点不为空,放入链表中,然后一直循环,直到链表为空。
public class Offer22 {
public static ArrayList<Integer> solution(TreeNode root){
LinkedList<TreeNode> list = new LinkedList<>();
ArrayList<Integer> reslut = new ArrayList<>();
if (root==null){
return null;
}
list.add(root);
while (!list.isEmpty()){
TreeNode node = list.pop();
reslut.add(node.val);
if (node.left!=null){
list.add(node.left);
}
if (node.right!=null){
list.add(node.right);
}
}
return reslut;
}
}
剑指Offer23
输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。
思路:根据后序遍历的特点,数组中最后一个元素为根节点的值,前面的元素为根节点的子节点,分别为根节点的左右子节点。然后将根节点与前面的元素相比较,如果小于更接待你放入左列表(新定义的),反之放入右节点(新定义)。如果在遍历时再次遇到比根节点小的元素,就返回false。然后在这两个列表中递归判断。
//将数组转化为列表
public static Boolean arrToArray(int[] sequence){
ArrayList<Integer> arrayList = new ArrayList<>();
if (sequence.length==0){
return false;
}
for (Integer num:sequence){
arrayList.add(num);
}
return verifyBST(arrayList);
}
private static Boolean verifyBST(ArrayList<Integer> arrayList) {
//如果数组的长度小于1,说明没有子节点符合条件
if (arrayList.size()<1){
return true;
}
ArrayList<Integer> leftArray = new ArrayList<>();
ArrayList<Integer> rightArray = new ArrayList<>();
int i = 0;
//找出根节点的值
Integer num = arrayList.get(arrayList.size() - 1);
//小于根节点放入leftArray
while (num>arrayList.get(i)){
leftArray.add(arrayList.get(i++));
}
//小于根节点放入rightArray
while (num<arrayList.get(i)){
rightArray.add(arrayList.get(i++));
}
//如果没有遍历完列表,说明不符合条件
if (i<arrayList.size()-1){
return false;
}
//循环判断子数组是否符合条件
return verifyBST(leftArray)&&verifyBST(rightArray);
}
shiro
shiro是apache旗下的一款开源框架,它将软件系统的安全认证抽取出来,实现用户的权限认证,授权,加密,会话,管理等功能,组成了一个通用的安全认证的框架
shiro的架构
-
Subject (org.apache.shiro.subject.Subject)
Subject即主体
,外部应用与subject进行交互,subject记录了当前操作用户,将用户的概念理解为当前操作的主体,可能是一个通过浏览器请求的用户,也可能是一个运行的程序。 Subject在shiro中是一个接口,接口中定义了很多认证授相关的方法,外部程序通过subject进行认证授,而subject是通过SecurityManager安全管理器进行认证授权 -
SecurityManager (org.apache.shiro.mgt.SecurityManager)
SecurityManager即安全管理器
,对全部的subject进行安全管理,它是shiro的核心,负责对所有的subject进行安全管理。 -
Authenticator (org.apache.shiro.authc.Authenticator)
Authenticator即认证器
,对用户身份进行认证,Authenticator是一个接口,shiro提供ModularRealmAuthenticator实现类,通过ModularRealmAuthenticator基本上可以满足大多数需求,也可以自定义认证器。 -
Authorizer (org.apache.shiro.authz.Authorizer)
Authorizer即授权器
,用户通过认证器认证通过,在访问功能时需要通过授权器判断用户是否有此功能的操作权限。 -
SessionManager (org.apache.shiro.session.mgt.SessionManager)
sessionManager即会话管理
,shiro框架定义了一套会话管理,它不依赖web容器的session,所以shiro可以使用在非web应用上,也可以将分布式应用的会话集中在一点管理,此特性可使它实现单点登录 -
SessionDAO (org.apache.shiro.session.mgt.eis.SessionDAO)
SessionDAO即会话dao
,是对session会话操作的一套接口,比如要将session存储到数据库,可以通过jdbc将会话存储到数据库。 -
CacheManager (org.apache.shiro.cache.CacheManager)
CacheManager即缓存管理
,将用户权限数据存储在缓存,这样可以提高性能。 -
Realms (org.apache.shiro.realm.Realm)
Realm即领域
,相当于datasource数据源,securityManager进行安全认证需要通过Realm获取用户权限数据,比如:如果用户身份数据在数据库那么realm就需要从数据库获取用户身份信息。
整合思路
springboot整合shiro
导入依赖
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring-boot-starter</artifactId>
<version>1.5.3</version>
</dependency>
创建shiro的配置环境
创建shiroFilter , 负责拦截所有请求
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(SecurityManager securityManager){
//创建shiro的filter
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
//注入安全管理器
shiroFilterFactoryBean.setSecurityManager(securityManager);
return shiroFilterFactoryBean;
}
//配置安全管理器
@Bean
public DefaultWebSecurityManager getSecurityManager(Realm realm){
DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
defaultWebSecurityManager.setRealm(realm);
return defaultWebSecurityManager;
}
//自定义realm
@Bean
public Realm getRealm(){
return new CustomerRealm;
}
创建自定义CustomerRealm继承AuthorizingRealm(授权领域)重写两个方法,认证和授权
public class CustomerRealm extends AuthorizingRealm {
//处理授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
return null;
}
//处理认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws
AuthenticationException {
return null;
}
}
.编写控制器跳转至index.html
@Controller
public class IndexController {
@RequestMapping("index")
public String index(){
System.out.println("跳转至主页");
return "index";
}
}
、
修改控制权限
在shiro配置文件中修改权限过滤器
Map<String ,String > map = new HashMap<>();
//设置为锅炉所有的请求
map.put("/**","authc");
//设置默认的认证资源为index主页面
shiroFilterFactoryBean.setLoginUrl("/user/index");
常见的过滤器
认证的实现
来发登陆页面
开发Controller
@RequestMapping("login")
public String login(String username ,String password , String code,HttpSession session){
String code1 = (String) session.getAttribute("code");
try {
if (code.equalsIgnoreCase(code1)) {
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
subject.login(token);
return "redirect:/index.jsp";
}else {
throw new RuntimeException("验证码不正确");
}
}catch (UnknownAccountException e){
e.printStackTrace();
System.out.println("账户错误");
}catch (IncorrectCredentialsException e){
e.printStackTrace();
System.out.println("密码错误");
}catch (RuntimeException e){
System.out.println(e.getMessage());
}
return "login";
}
退出系统
@Controller
@RequestMapping("user")
public class UserController {
/**
* 退出登录
*
*/
@RequestMapping("logout")
public String logout(){
Subject subject = SecurityUtils.getSubject();
subject.logout();//退出用户
return "redirect:/login.jsp";
}
}
MD5、salt、散列1024
建立数据库
引入依赖
<!--mybatis相关依赖-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.2</version>
</dependency>
<!--mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.38</version>
</dependency>
<!--druid-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.19</version>
</dependency>
properties配置文件
spring.mvc.view.prefix=/
spring.mvc.view.suffix=.jsp
#新增配置
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/shiro?characterEncoding=UTF-8
spring.datasource.username=root
spring.datasource.password=root
mybatis.type-aliases-package=com.baizhi.springboot_jsp_shiro.entity
创建实体对象
@Data
@Accessors(chain = true)
@AllArgsConstructor
@NoArgsConstructor
public class User {
private String id;
private String username;
private String password;
private String salt;
}
创建dao接口
创建xml文件
创建service接口
创建serviceImp实现类
创建salt工具类
public class SaltUtils {
/**
* 生成salt的静态方法
* @param n
* @return
*/
public static String getSalt(int n){
char[] chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567890!@#$%^&*()".toCharArray();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < n; i++) {
char aChar = chars[new Random().nextInt(chars.length)];
sb.append(aChar);
}
return sb.toString();
}
}
开发service实现类
@Service
@Transactional
public class UserServiceImpl implements UserService {
@Autowired
private UserDAO userDAO;
@Override
public void register(User user) {
//处理业务调用dao
//1.生成随机盐
String salt = SaltUtils.getSalt(8);
//2.将随机盐保存到数据
user.setSalt(salt);
//3.明文密码进行md5 + salt + hash散列
Md5Hash md5Hash = new Md5Hash(user.getPassword(),salt,1024);
user.setPassword(md5Hash.toHex());
userDAO.save(user);
}
}
开发Controller
@Controller
@RequestMapping("user")
public class UserController {
@Autowired
private UserService userService;
/**
* 用户注册
*/
@RequestMapping("register")
public String register(User user) {
try {
userService.register(user);
return "redirect:/login.jsp";
}catch (Exception e){
e.printStackTrace();
return "redirect:/register.jsp";
}
}
}
开发在工厂中获取bean对象的工具类
@Component
public class ApplicationContextUtils implements ApplicationContextAware {
private static ApplicationContext context;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.context = applicationContext;
}
//根据bean名字获取工厂中指定bean 对象
public static Object getBean(String beanName){
return context.getBean(beanName);
}
}
修改自定义realm在这里插入代码片
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
System.out.println("==========================");
//根据身份信息
String principal = (String) token.getPrincipal();
//在工厂中获取service对象
UserService userService = (UserService) ApplicationContextUtils.getBean("userService");
//根据身份信息查询
User user = userService.findByUserName(principal);
if(!ObjectUtils.isEmpty(user)){
//返回数据库信息
return new SimpleAuthenticationInfo(user.getUsername(),user.getPassword(),
ByteSource.Util.bytes(user.getSalt()),this.getName());
}
return null;
}
修改ShiroConfig中realm使用凭证匹配器以及hash散列
@Bean
public Realm getRealm(){
CustomerRealm customerRealm = new CustomerRealm();
//设置hashed凭证匹配器
HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
//设置md5加密
credentialsMatcher.setHashAlgorithmName("md5");
//设置散列次数
credentialsMatcher.setHashIterations(1024);
customerRealm.setCredentialsMatcher(credentialsMatcher);
return customerRealm;
}
授权的实现
<shiro:hasAnyRoles name="user,admin">
<li><a href="">用户管理</a>
<ul>
<shiro:hasPermission name="user:add:*">
<li><a href="">添加</a></li>
</shiro:hasPermission>
<shiro:hasPermission name="user:delete:*">
<li><a href="">删除</a></li>
</shiro:hasPermission>
<shiro:hasPermission name="user:update:*">
<li><a href="">修改</a></li>
</shiro:hasPermission>
<shiro:hasPermission name="user:find:*">
<li><a href="">查询</a></li>
</shiro:hasPermission>
</ul>
</li>
</shiro:hasAnyRoles>
<shiro:hasRole name="admin">
<li><a href="">商品管理</a></li>
<li><a href="">订单管理</a></li>
<li><a href="">物流管理</a></li>
</shiro:hasRole>
方法条应授权
- @RequiresRoles 用来基于角色进行授权
- @RequiresPermissions 用来基于权限进行授权
@RequiresRoles(value={"admin","user"})//用来判断角色 同时具有 admin user
@RequiresPermissions("user:update:01") //用来判断权限字符串
@RequestMapping("save")
public String save(){
System.out.println("进入方法");
return "redirect:/index.jsp";
}
修改realm
public class CustomerRealm extends AuthorizingRealm {
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
//获取身份信息
String primaryPrincipal = (String) principals.getPrimaryPrincipal();
System.out.println("调用授权验证: "+primaryPrincipal);
//根据主身份信息获取角色 和 权限信息
UserService userService = (UserService) ApplicationContextUtils.getBean("userService");
User user = userService.findRolesByUserName(primaryPrincipal);
//授权角色信息
if(!CollectionUtils.isEmpty(user.getRoles())){
SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
user.getRoles().forEach(role->{
simpleAuthorizationInfo.addRole(role.getName());
//权限信息
List<Perms> perms = userService.findPermsByRoleId(role.getId());
if(!CollectionUtils.isEmpty(perms)){
perms.forEach(perm->{
simpleAuthorizationInfo.addStringPermission(perm.getName());
});
}
});
return simpleAuthorizationInfo;
}
return null;
}
}
使用shiro中默认EhCache实现缓存
减轻数据库的压力
引入依赖
<!--引入shiro和ehcache-->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-ehcache</artifactId>
<version>1.5.3</version>
</dependency>
开启缓存
//3.创建自定义realm
@Bean
public Realm getRealm(){
CustomerRealm customerRealm = new CustomerRealm();
//修改凭证校验匹配器
HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
//设置加密算法为md5
credentialsMatcher.setHashAlgorithmName("MD5");
//设置散列次数
credentialsMatcher.setHashIterations(1024);
customerRealm.setCredentialsMatcher(credentialsMatcher);
//开启缓存管理器
customerRealm.setCachingEnabled(true);
customerRealm.setAuthorizationCachingEnabled(true);
customerRealm.setAuthorizationCachingEnabled(true);
customerRealm.setCacheManager(new EhCacheManager());
return customerRealm;
}