解决shiro的登录成功后跳转到自定义error.html的问题

2023-05-16

解决shiro的登录成功后跳转到error.html

1. 先说一下问题现象:saas项目中,登录成功之后,跳转了error.html,停顿一会儿后进入主页面。

2. 说一下我处理这个问题的步骤:

  • 搞清楚这个页面登录的流程。
  • 问题产生的原因,产生的时机

3. 根据上边的思路先处理这个saas平台登录的流程,梳理如下:

  • 项目的存在LoginController。存在接口login、main、mianIndex等接口。并且该controller对局部异常做了处理:
/**
 * 当前controller类中的异常处理,主要作用于用户登录 ,其他操作请勿写在该类中
 * 
 * @param req
 * @param e
 * @return
 * @throws Exception
 */
@ExceptionHandler(value = BusinessException.class)
public ModelAndView ErrorHandler(HttpServletRequest req, BusinessException e) throws Exception {
	ModelAndView view = new ModelAndView();
	view.addObject("msg", "登录失败" + e.getMsg());
	view.setViewName("error");
	return view;
}
  • 项目使用了shiro,所以会在登录的时候先进行Filter过滤。项目存在ShiroConfig、CustomAccessFilter
  • CustomAccessFilter继承了FormAuthenticationFilter,所以登录会先执行重新的方法:onAccessDenied 然后执行到executeLogin,执行重写的onLoginSuccess,最后接着执行onAccessDenied方法中未完成的内容。
/**
 *
 */
package cn.etcom.security.filter;

import java.util.Date;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import cn.etcom.entity.security.ActiveUser;
import cn.etcom.security.ShiroUtils;
import cn.etcom.util.prop.WebDefineProperties;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.ThreadContext;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
import org.apache.shiro.web.filter.authc.LogoutFilter;
import org.apache.shiro.web.util.WebUtils;
import org.crazycake.shiro.RedisSessionDAO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import cn.etcom.entity.SystemLog;
import cn.etcom.service.log.SystemLogService;
import cn.etcom.service.log.impl.SystemLogServiceImpl;
import cn.etcom.util.LoggerUtils;
import cn.etcom.util.enums.ActionEnum;
import cn.etcom.util.spring.SpringUtil;

/**
 * @author admin
 *
 */
public class CustomAccessFilter extends FormAuthenticationFilter {
    private static final Logger logger = LoggerFactory.getLogger(LogoutFilter.class);

    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
        if (isLoginRequest(request, response)) { // 判断是否登录
            if (isLoginSubmission(request, response)) { // 判断是否为post访问
                SystemLogService systemLogService = SpringUtil.getBean(SystemLogServiceImpl.class);
                String ip = LoggerUtils.getCliectIp((HttpServletRequest) request);
                HttpSession session = ((HttpServletRequest) request).getSession();
                //Session session = ShiroUtils.getSession();
                session.setAttribute("ip", ip);
                String username = super.getUsername(request);
                WebDefineProperties wdp = SpringUtil.getBean(WebDefineProperties.class);
                String s = ShiroUtils.getSession().getId().toString();
                boolean flag = executeLogin(request, response);
                logger.debug("--------------用户登录系统:{},false:登录成功,true:登录失败----------------------", flag);
                if (!flag) {

                    Subject subject = getSubject(request, response);
                    ActiveUser activeUser = (ActiveUser) subject.getPrincipal();
//                    System.out.println(activeUser);
                    if (wdp.getKickout()) ShiroUtils.kickout(activeUser, s);
                    SystemLog systemLog = new SystemLog();
                    systemLog.setRequestip(ip).setUrl(request.getLocalAddr() + "/login").setHttpmethod("POST")
                            .setType("normal").setActionName("用户登录").setAction(ActionEnum.LOGIN.toString())
                            .setOpTime(new Date()).setOpUser(username).setDescription(ActionEnum.LOGIN + ":系统登入")
                            .setTenantId(activeUser != null ? activeUser.getTenantId() : "");
                    systemLogService.saveLog(systemLog);
                    return flag;
                } else {
                    return true;
                }
            } else {
                // sessionID已经注册,但是并没有使用post方式提交
                return true;
            }
        } else {
            saveRequestAndRedirectToLogin(request, response);
        }
        return false;
    }

    @Override
    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
//        if (isLoginRequest(request, response)) {
        return super.isAccessAllowed(request, response, mappedValue);
//        } else {
//            String host = request.getParameter("host");
//            if("1.1.1.1".equals(host) )
//
//                return true;
//             else
//                 return false;
//        }
        //return true;
    }

    @Override
    protected boolean onLoginSuccess(AuthenticationToken token, Subject subject, ServletRequest request, ServletResponse response) throws Exception {
        WebUtils.getAndClearSavedRequest(request);
        WebUtils.redirectToSavedRequest(request, response, "/");
        return false;
    }
}

— shiro 配置文件

package cn.etcom.security;

import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import cn.etcom.security.filter.CustomAccessFilter;
import cn.etcom.security.filter.CustomLogoutFilter;
import cn.etcom.security.filter.SysUserFilter;
import cn.etcom.security.listener.ShiroSessionListener;
import cn.etcom.util.base.constant.Constants;
import cn.etcom.web.properties.FileUploadProperteis;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.session.SessionListener;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.crazycake.shiro.RedisCacheManager;
import org.crazycake.shiro.RedisManager;
import org.crazycake.shiro.RedisSessionDAO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.context.annotation.Primary;

import javax.servlet.Filter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;


@Configuration
public class ShiroConfig {
    private static final Logger logger = LoggerFactory.getLogger(ShiroConfig.class);

    private final static String algorithmName = "md5";
    private final static int hashIterations = 2;

    private final static String CACHE_KEY = Constants.CACHE_KEY;
    private final static String SESSION_KEY = Constants.SESSION_KEY;
    private final static int EXPIRE = 1800;

    @Value("${spring.redis.host}")
    private String host;
    @Value("${spring.redis.port}")
    private int port;
    @Value("${spring.redis.timeout}")
    private int timeout;
    @Value("${spring.redis.password}")
    private String password;
    @Autowired
    private FileUploadProperteis fileUploadProperteis;

    @Bean
    public RedisManager redisManager() {
        RedisManager redisManager = new RedisManager();
        redisManager.setHost(this.host);
        redisManager.setPort(port);
        redisManager.setTimeout(timeout);
        redisManager.setPassword(password);
        return redisManager;
    }

    @Primary
    @Bean("redisCacheManager")
    public RedisCacheManager cacheManager() {
        RedisCacheManager redisCacheManager = new RedisCacheManager();
        redisCacheManager.setRedisManager(redisManager());
        redisCacheManager.setKeyPrefix(CACHE_KEY);
        // 配置缓存的话要求放在session里面的实体类必须有个id标识
        redisCacheManager.setPrincipalIdFieldName("userid");
        //redisCacheManager.setValueSerializer(myRedisSerializer());
        return redisCacheManager;
    }

    @Bean
    public ShiroSessionIdGenerator sessionIdGenerator() {
        return new ShiroSessionIdGenerator();
    }

    /*
        @Bean
        public MyRedisSerializer myRedisSerializer(){
            return new MyRedisSerializer();
        }
        */
    @Bean
    public RedisSessionDAO redisSessionDAO() {
        RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
        redisSessionDAO.setRedisManager(redisManager());
        redisSessionDAO.setSessionIdGenerator(sessionIdGenerator());
        redisSessionDAO.setKeyPrefix(SESSION_KEY);
        redisSessionDAO.setExpire(EXPIRE);
        //  redisSessionDAO.setValueSerializer(myRedisSerializer());
        return redisSessionDAO;
    }

/*

    @Bean(name="ehCacheManager")
    public EhCacheManager ehCacheManager() {
        EhCacheManager cacheManager = new EhCacheManager();
        cacheManager.setCacheManagerConfigFile(cacheFile);
        return cacheManager;
    }
*/

/*

    @Bean
    public SimpleCookie getSimpleCookie() {
        SimpleCookie cookie = new SimpleCookie("shiro.sesssion");
        cookie.setMaxAge(EXPIRE);
        cookie.setPath("/");
        return cookie;
    }
*/


    @Bean("lifecycleBeanPostProcessor")
    public static LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }
/*

  @Bean
    @DependsOn("lifecycleBeanPostProcessor")
    public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        advisorAutoProxyCreator.setProxyTargetClass(true);
        return advisorAutoProxyCreator;
    }
*/

    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }

    @Bean(name = "credentialsMatcher")
    public RetryLimitHashedCredentialsMatcher hashedCredentialsMatcher() {
        RetryLimitHashedCredentialsMatcher hashedCredentialsMatcher = new RetryLimitHashedCredentialsMatcher();
        // 散列算法:这里使用MD5算法;
        hashedCredentialsMatcher.setHashAlgorithmName(algorithmName);
        hashedCredentialsMatcher.setHashIterations(hashIterations);
        return hashedCredentialsMatcher;
    }

    @Bean
    public CustomRealm realm() {
        CustomRealm shiroRealm = new CustomRealm();
        shiroRealm.setCachingEnabled(true);
        //启用身份验证缓存,即缓存AuthenticationInfo信息,默认false
        //shiroRealm.setAuthenticationCachingEnabled(true);
        shiroRealm.setAuthorizationCachingEnabled(true);
        //shiroRealm.setAuthenticationCacheName("authenticationCache");
        shiroRealm.setAuthorizationCacheName("authorizationCache");
        shiroRealm.setCredentialsMatcher(hashedCredentialsMatcher());
        return shiroRealm;
    }

    @Bean
    public SessionManager getDefaultWebSessionManager() {
        DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
        sessionManager.setSessionDAO(redisSessionDAO());
     /*   Collection<SessionListener> listeners = new ArrayList<>();
        listeners.add(sessionListener());
        sessionManager.setSessionListeners(listeners);
        sessionManager.setGlobalSessionTimeout(EXPIRE);
        sessionManager.setDeleteInvalidSessions(true);
        sessionManager.setSessionIdUrlRewritingEnabled(false);
        sessionManager.setSessionValidationInterval(10000);
        sessionManager.setSessionValidationSchedulerEnabled(true);*/
        //sessionManager.setSessionIdCookie(getSimpleCookie());
        sessionManager.setSessionIdUrlRewritingEnabled(false);
        return sessionManager;
    }

    @Bean
    public SecurityManager securityManager() {

        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(realm());
        securityManager.setSessionManager(getDefaultWebSessionManager());
        securityManager.setCacheManager(cacheManager());
        return securityManager;
    }


    @Bean(name = "shiroFilter")
    public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        // Shiro的核心安全接口
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        shiroFilterFactoryBean.setLoginUrl("/login");
        //shiroFilterFactoryBean.setSuccessUrl("/");
        shiroFilterFactoryBean.setUnauthorizedUrl("/error");
        Map<String, Filter> m = new ConcurrentHashMap<>();
        // 实现登出日志记录
        m.put("logout", new CustomLogoutFilter());
        m.put("authc", new CustomAccessFilter());
        m.put("sysUser", new SysUserFilter());
        shiroFilterFactoryBean.setFilters(m);
        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
        filterChainDefinitionMap.put("/favicon.ico", "anon");
        filterChainDefinitionMap.put("/", "anon");
        filterChainDefinitionMap.put(fileUploadProperteis.getStaticPath(),"anon");
        filterChainDefinitionMap.put("/error", "anon");
        filterChainDefinitionMap.put("/outside/access", "anon");
        filterChainDefinitionMap.put("/outside/getToken", "anon");
        filterChainDefinitionMap.put("/auth", "anon");
        filterChainDefinitionMap.put("/login/sub", "anon");
        filterChainDefinitionMap.put("/profile/*", "anon");
        filterChainDefinitionMap.put("/swagger/**", "anon");
        filterChainDefinitionMap.put("/resources/**", "anon");
        filterChainDefinitionMap.put("/actuator", "anon");
        filterChainDefinitionMap.put("/actuator/health", "anon");
        filterChainDefinitionMap.put("/actuator/info", "anon");
        filterChainDefinitionMap.put("/dept/findAll", "anon");
        filterChainDefinitionMap.put("/logout", "logout");
        filterChainDefinitionMap.put("/**", "authc");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return shiroFilterFactoryBean;
    }

    @Bean(name = "shiroDialect")
    public ShiroDialect shiroDialect() {
        return new ShiroDialect();
    }

    /**
     * 在线人统计
     *
     * @return
     */
    @Bean("sessionListener")
    public ShiroSessionListener sessionListener() {
        ShiroSessionListener sessionListener = new ShiroSessionListener();
        return sessionListener;
    }
}

4. 处理这个问题的时候,我定位问题一直在后台的Filter的onLoginSuccess() 方法的重定向路径上。
其实问题的原因是:shiro中存在某种规则,onLoginSuccess() 方法第一次重定向后,浏览器路径会拼接:;JSESSIONID=XXXX 所以特殊字符; 导致访问请求变成:http://localhost:10003/;JSESSIONID=login_token_9b0ceaba-4448-469b-9652-a9eaae6abe10/。
导致异常400 会被项目异常拦截,然后访问error.html.

在error.html中存在setTimeOut定时器。2秒后跳转window.location.href="/"。这样会访问到index.html,然后如果登录成功会访问:/main 接口。如果登录失败会回到登录页面。

5. 根据问题点处理问题:

DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
sessionManager.setSessionDAO(redisSessionDAO());
sessionManager.setSessionIdUrlRewritingEnabled(false);

6. 了解到的知识点:

  • 我们写的CustomAccessFilter继承了FormAuthenticationFilter。实际的最开始需要重写的方法是:onAccessDenied()。实现核心的处理。但是如果不重写onLoginSuccess()这个方法,这个登录成功后访问的路径是:之前的存在session中的原请求,也就是login。浏览器会访问:http://localhost:10003/login
    重写这个方法的时候,首先清理了原有的请求地址,然后重定向到 “/” ,如果没有;jsXXX 会访问到index.html ,然后访问/main 到main.html

  • 第二点,就是;jsXXX这个东西拼接的地方在:ShiroHttpServletResponse 里。

在这里插入图片描述

  • 解决这个问题的关键点:上边也写了就是:
DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
sessionManager.setSessionIdUrlRewritingEnabled(false);

或者:新建MyShiroHttpServletResponse继承ShiroHttpServletResponse

重写其方法encodeRedirectURL和toEncoded

  • 1
  • 1

参考文章地址:

https://blog.csdn.net/ruanes/article/details/108417460

https://blog.csdn.net/weixin_34128534/article/details/92655476

https://blog.csdn.net/qq_39727959/article/details/106350249

https://www.cnblogs.com/sevenlin/p/sevenlin_shiro20150924.html

https://www.jianshu.com/p/a157c666159b

  1. 1
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

解决shiro的登录成功后跳转到自定义error.html的问题 的相关文章

  • android顶部回退按钮的实现

    最近看来好多关于android顶部导航栏回退的实现 如下图效果 点击返回上级页面 xff0c 网上的大部分都实现特别繁琐 xff0c 其实安卓自带BUFF 在Manifest清单文件中一句代码就能搞定 xff0c 特别easy xff0c
  • 树莓派与Android客户端进行socket通信

    首先 xff0c 需要对树莓派进行配置 xff0c 使其成为AP热点 xff0c 这里我用的树莓派3B自带wifi蓝牙模块 xff0c 树莓派3B作AP热点的方法具体参考https blog csdn net u014271612 arti
  • android客户端控制树莓派GPIO点亮LED灯

    首先需要android客户端与树莓派进行连接 xff0c 树莓派与android客户端利用wifi连接并进行socket通信请参考我的另一片文章 xff1a https mp csdn net postedit 79911322 树莓派与A
  • 百度2014校园招聘 软件研发工程师 笔试题

    一 简答题 xff08 本题共30 xff09 1 动态链接库和静态链接库分别有什么优缺点 xff1f xff08 10 xff09 2 轮询任务调度与抢占式任务调度的区别 xff1f xff08 10 xff09 3 请列出数据库中常用的
  • java基础编程案例

    java编程案例 案例一 xff1a 飞机票查看优惠系统案例二 xff1a 获取素数案例三 xff1a 验证码模块案例四 xff1a 数组元素的复制案例五 xff1a 评委打分案例六 xff1a 数字加密程序案例七 xff1a 模拟双色球系
  • Java基础之集合框架--Collections工具类之max()方法

    max 方法一个参数的源码 xff1a public static lt T extends Object amp Comparable lt super T gt gt T max Collection lt extends T gt c
  • python创建一个txt文件

    创建一个txt文件 xff0c 文件名为mytxtfile 并向文件写入msg 注意文件的路径不要错 xff0c 还有文件的格式 创建一个txt文件 xff0c 文件名为mytxtfile 并向文件写入msg def text create
  • Android--Jetpack的使用(一)

    目录 1 ViewModel 2 ViewModel 43 LiveData 3 ViewModel 43 LiveData 43 dataBinding 4 ViewModel 43 SavedStateHandle 43 LiveDat
  • Git 常用命令

    一 Git常用命令 1 配置用户名 xff08 上传代码的用户名 xff09 xff1a git config global user name 34 ljs 34 2 配置用户邮箱 xff08 其他作者联系你的邮箱 xff09 xff1a
  • 游戏开发图书推荐--我读过的技术经典图书

    很多同学问我学游戏开发应该看些什么书 xff0c 我在这里抛砖引玉 xff0c 给一份推荐表 xff0c 希望大家共同提高 由于本人英文不太好 xff0c 推荐的大部书籍都是国人编写的 xff0c 有些经典的外文图书可能是翻译不好 xff0
  • Git中使用.gitignore忽略文件的推送

    1 简介 在使用Git管理自己的代码版本时 xff0c 由于编译生成的中间文件 xff0c Git使用SHA 1算法来对文件进行加密 xff0c 进而得出来一个40位的十六进制加密字符串 325525d8b1f67b5ddd37956a8a
  • AFNetWorking3.0处理请求头和请求内容

    今天要处理用户的相关信息 xff0c 需要在HTTP请求中添加请求头 xff0c 网上大部分资料都是针对AFNetWorking2 0的 xff0c 我用3 0版本实现了相关功能 xff0c 见下面代码 首先是请求的URL xff0c sp
  • chrome浏览器安装插件,提示程序包无效

    chrome浏览器安装插件的时候 xff0c 如果提示 程序包无效 xff1a CRX HEADER INVALID xff0c 导致插件安装不上去 xff0c 这个时候该怎么办呢 xff1f 通常 xff0c 这种错误在chrome浏览器
  • viewpage+radiogroup

    lt xml version 61 34 1 0 34 encoding 61 34 utf 8 34 gt lt LinearLayout xmlns android 61 34 http schemas android com apk
  • 线程执行设置超时时间

    import java util concurrent 记录 xff0c 备忘 线程执行设置超时时间 public class Main2 定义线程池 xff0c 推荐手动创建线程池 xff1a https blog csdn net LL
  • Java集合工具类Collections常用方法详解

    文章目录 1 Collections介绍2 Collections常用方法2 1 reverse 2 2 sort 2 3 swap 2 4 min 和max 2 5 copy 2 6 fill 2 7 replaceAll 2 8 shu
  • 智慧小区智能物业管理系统综合解决方案

    因为传统的办公方式效率低 xff0c 工作强度大 人们需耗费大量的时间和精力去手工处理那些繁杂 重复的工作 xff0c 而手工处理的延时和差错 xff0c 正是现代化管理中应该去除的弊端 又由于物业管理企业的启动基金不足 xff0c 多种经
  • LAMP基础搭建

    目录 一 LAMP 1 LAMP环境 2 组成部分 xff08 1 xff09 Linux xff08 平台 xff09 xff08 2 xff09 Apache xff08 前台 xff09 xff08 3 xff09 Mysq xff0
  • python获取子窗口句柄

    2022 09 17 python获取子窗口句柄 python获取窗口句柄 python获取进程 python获取电脑微信小游戏的窗口句柄 上图为按键精灵的工具 python3 xff0c 简单的获取了下句柄 xff0c 想改改内存的 xf
  • Linux多线程编程(三)-----生产者与消费者(条件变量,信号量)

    Linux多线程编程 xff08 一 xff09 xff1a http blog csdn net llzk article details 55670172 Linux多线程编程 xff08 二 xff09 xff1a http blog

随机推荐

  • 微策略的笔试题

    觉得在收获Offer的季节应该为自己积累些人品了 xff0c 在这里将今天的情况向所有求Offer的童鞋分享下 从上个周末开始反应迟钝的我终于有了些求Offer的感觉 xff0c 几天参加了4场面试 xff0c 基本上没觉得有很大的挑战 x
  • 线程池定时任务添加任务以及停止线程

    最近有个需求 就是项目启动的时候需要创建个线程池去执行 而且有时间周期 而且根绝不同的情况可以随时通过接口停止该线程 1首先创建个线程池 默认核心为10 static ScheduledExecutorService threadPool
  • 冰冻三尺非一日之寒-自学篇 浅谈个人学习方法

    昨晚还在看比赛 xff08 war3 xff09 xff0c 小源跑过来问我明天1024 xff0c 不写篇文章么 xff0c 想想也是 xff0c 1024这也算个热点 xff0c 赶紧来蹭蹭 xff0c 哈 xff0c 开个玩笑 上次谈
  • 【附源码】Java计算机毕业设计社区团购服务系统(程序+LW+部署)

    项目运行 环境配置 xff1a Jdk1 8 43 Tomcat7 0 43 Mysql 43 HBuilderX xff08 Webstorm也行 xff09 43 Eclispe xff08 IntelliJ IDEA Eclispe
  • iOS---iOS10适配iOS当前所有系统的远程推送

    一 iOS推送通知简介 众所周知苹果的推送通知从iOS3开始出现 每一年都会更新一些新的用法 譬如iOS7出现的Silent remote notifications 远程静默推送 iOS8出现的Category 分类 也可称之为快捷回复
  • iOS总结_UI层自我复习总结

    UI层复习笔记 在main文件中 xff0c UIApplicationMain函数一共做了三件事 根据第三个参数创建了一个应用程序对象 默认写nil xff0c 即创建的是UIApplication类型的对象 xff0c 此对象看成是整个
  • 【疯狂造轮子-iOS】JSON转Model系列之一

    1 前言 之前一直看别人的源码 xff0c 虽然对自己提升比较大 xff0c 但毕竟不是自己写的 xff0c 很容易遗忘 这段时间准备自己造一些轮子 xff0c 主要目的还是为了提升自身实力 xff0c 总不能一遇到问题就Google 之前
  • 解决fastboot 刷 system.img 尺寸限制问题

    fastboot S xxxM flash system system img 其中 S 后面为单次上传大小 C platform tools gt fastboot S 300M flash system system img sendi
  • 修改Gnome Terminal窗口的默认大小

    修改Gnome Terminal窗口的默认大小 以前一直比较别扭的是 xff0c Gnome Terminal窗口打开时总那么小 曾经找半天也不知道在哪里改 xff0c 甚至在官方论坛里也没查到 今天偶然间想到那个Preferred App
  • 前端基础练习题

    变量命名规则 xff1a 1 只能由字母 数字 下划线 美元符号组成 xff0c 并且不能以数字开头 2 变量命名要有意义 xff0c 杜绝a01 b0046 3 变量遵循小驼峰规则 第一个单词全小写 xff0c 从第二个单词开始 xff0
  • Unity5-ABSystem(三):AssetBundle加载

    Unity特殊路径 ResourcesStreamingAssetsPathPersistentDataPathDataPath 同步加载 核心函数安卓平台下不能同步加载问题示例 异步加载 核心函数示例WWW异步加载 资源加载 核心函数 加
  • Unity5-ABSystem(五):AssetBundle内存

    AssetBundle内存占用 建议 实测 www加载实测LoadFromFile加载实测 建议 AssetBundle内存占用 先上图 xff0c Don t panic 我们从AssetBundle中加载资源一般会经过三个步骤 xff1
  • Java中String字符串长度

    String类是Java中最为常用的类 xff0c 我们知道String是个final类 xff0c 不能修改内容 但是String类型是否有长度限制呢 xff0c 下面来一探究竟 想要搞清楚这个问题 xff0c 首先我们需要翻阅一下Str
  • 安装BBR时出现Error: Install elrepo failed, please check it.

    安装BBR时出现Error Install elrepo failed please check it Press any key to start or Press Ctrl 43 C to cancel curl 35 SSL conn
  • mac卸载mysql教程(按照步骤可完全卸载)

    Mac下卸载mysql的方法 xff1a 大部分卸载是因为版本高 1 关闭mysql 查看mysql是否启动 xff1a ps ef grep mysql 2 输入 xff1a kill 9 然后回车 xff0c 关闭mysql 3 卸载
  • 全网最简单Win10桌面美化教程,只需4步!!

    时间过得真滴快呀 xff01 咋眼就10月了 不知道国庆期间 小伙伴们是外出旅游 还是宅在家里哪里也没去 或者更悲催一点 还在国庆加班抑或因为疫情正在隔离 无论大家处于任何状态 小七都要在这里祝大家 xff1a 国庆节快乐 吉祥话说完了 下
  • Pycharm配置Jupyter Notebook实现本地开发与调试

    Pycharm专业版中集成了Jupyter Notebook xff0c 方便用户编辑 xff0c 执行和调试Notebook代码 xff0c 并检查执行输出 个人感觉 xff0c 相比于Jupyter提供的网页编辑器 xff0c Pych
  • Zookeeper选举机制介绍

    ZooKeeper是一个高可用的分布式协调服务 xff0c 它的核心功能之一就是选举机制 当ZooKeeper集群中的一个节点宕机时 xff0c 需要通过选举机制来选出一个新的leader节点 xff0c 确保集群的正常运行 下面是ZooK
  • redis实现布隆过滤器

    Redis是一种基于内存的数据存储系统 xff0c 具有高性能 高可用性 高扩展性等特点 xff0c 因此被广泛用于实现布隆过滤器 以下是一种基于Redis实现布隆过滤器的方案 xff1a 创建一个长度为m的位数组 xff08 bit ar
  • 解决shiro的登录成功后跳转到自定义error.html的问题

    解决shiro的登录成功后跳转到error html 1 先说一下问题现象 xff1a saas项目中 xff0c 登录成功之后 xff0c 跳转了error html xff0c 停顿一会儿后进入主页面 2 说一下我处理这个问题的步骤 x