SpringBoot + Spring Security多种登录方式:账号+微信网页授权登录

大家好,我是宝哥!

一、概述

实现账号用户名+微信网页授权登录集成在Spring Security的思路,最重要的一点是要实现微信登录通过Spring Security安全框架时,不需要验证账号、密码。

二、准备工作

要实现该功能,首先需要掌握Spring Security框架和微信扫码登录接口相关技术,如果对这两块还不太熟悉,可以参考:

1、Springboot + Spring Security实现前后端分离登录认证及权限控制

  • https://blog.csdn.net/xue317378914/article/details/115318318

2、微信开放平台开发第三方授权登陆:微信扫码登录

  • https://blog.csdn.net/xue317378914/article/details/115318810

三、项目代码结构

a909efffe2a434c8567f6526985db8ad.png

四、Spring Security核心配置:WebSecurityConfig

在WebSecurityConfig中配置了用户名密码登陆的验证以及token授权登陆两种方式,并分别通过不同的拦截器和不同的验证方式来实现该功能。

@Configuration
@EnableWebSecurity
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {@Autowired MyAuthenticationnSuccessHandler myAuthenticationSuccessHandler;@Autowired MyAuthenticationFailureHandler myAuthenticationFailureHandler;@AutowiredWxAuthenticationnSuccessHandler wxAuthenticationnSuccessHandler;@AutowiredWxAuthenticationFailureHandler wxAuthenticationFailureHandler;@Autowired private DataSource dataSource;@AutowiredRedisOneNetUtil redisOneNetUtil;@Value("${companyLog.loginPage}")private String loginPage;@Beanpublic JdbcTokenRepositoryImpl tokenRepository() {JdbcTokenRepositoryImpl tokenRepository = new JdbcTokenRepositoryImpl();tokenRepository.setDataSource(dataSource);// tokenRepository.setCreateTableOnStartup(true); // 启动创建表,创建成功后注释掉return tokenRepository;}@BeanUserDetailsService customUserService() { // 注册UserDetailsService 的beanreturn new CustomUserServiceImpl();}@BeanUserDetailsService weChatUserService() { // 注册UserDetailsService 的beanreturn new WeChatUserServiceImpl();}/*** 此处给AuthenticationManager添加登陆验证的逻辑。* 这里添加了两个AuthenticationProvider分别用于用户名密码登陆的验证以及token授权登陆两种方式。* 在处理登陆信息的过滤器执行的时候会调用这两个provider进行登陆验证。*/@Overridepublic void configure(AuthenticationManagerBuilder auth) throws Exception {//用户名和密码登陆auth.userDetailsService(customUserService()).passwordEncoder(new BCryptPasswordEncoder());//微信openid登陆auth.authenticationProvider(weChatAuthenticationProvider());}//用户名和密码登陆处理/*@Beanpublic CustomAuthenticationProvider customAuthenticationProvider() {return new CustomAuthenticationProvider();}
*///微信openid登陆处理@Beanpublic WeChatAuthenticationProvider weChatAuthenticationProvider() {return new WeChatAuthenticationProvider();}/*** 添加微信openid登陆验证的过滤器*/@Beanpublic WeChatAuthenticationFilter weChatAuthenticationFilter() throws Exception {WeChatAuthenticationFilter filter = new WeChatAuthenticationFilter();filter.setAuthenticationManager(authenticationManagerBean());filter.setAuthenticationSuccessHandler(wxAuthenticationnSuccessHandler);filter.setAuthenticationFailureHandler(wxAuthenticationFailureHandler);return filter;}/*** 添加用户名和密码登陆验证的过滤器*/@Beanpublic CustomAuthenticationFilter customAuthenticationFilter() throws Exception {CustomAuthenticationFilter filter = new CustomAuthenticationFilter();filter.setAuthenticationManager(authenticationManagerBean());filter.setAuthenticationSuccessHandler(myAuthenticationSuccessHandler);filter.setAuthenticationFailureHandler(myAuthenticationFailureHandler);return filter;}/** 配置请求拦截 */@Overrideprotected void configure(HttpSecurity http) throws Exception {// http: // 192.168.1.225:8080/users/restPwdView?userid=6&taskcode=8grf3BHttpMethodFilter filter = new HttpMethodFilter();WeChatAuthenticationFilter wechatFilter = weChatAuthenticationFilter();CustomAuthenticationFilter customFilter = customAuthenticationFilter();ValidateCodeFilter validateCodeFilter = new ValidateCodeFilter();validateCodeFilter.setAuthenticationFailureHandler(myAuthenticationFailureHandler);// http.httpBasic()    //httpBasic登录 BasicAuthenticationFilter// 必须在注册之后的过滤器之间才能安插过滤器http.addFilterBefore(filter, UsernamePasswordAuthenticationFilter.class).addFilterBefore(wechatFilter, UsernamePasswordAuthenticationFilter.class).addFilterBefore(customFilter, UsernamePasswordAuthenticationFilter.class).addFilterAfter(validateCodeFilter, HttpMethodFilter.class)//表单登录,loginPage为登录请求的url,loginProcessingUrl为表单登录处理的URL.formLogin().loginPage(loginPage)// 登录需要经过的url请求.loginProcessingUrl("/user/login").loginProcessingUrl("/wechat/weChatLogin")//.successHandler(myAuthenticationSuccessHandler)//.failureHandler(myAuthenticationFailureHandler).and().authorizeRequests().antMatchers(loginPage,"/comMonAssessScreens","/comMonAssessScreen","/alarmConfiguration/ifCheck","/logOut","/code/image","/meterData/insertElecMeterDataList","/meterDataCreate/*","/common/**","/common/js/**","/wechat/login","/wechat/weChatLogin_epf","/wechat/userLogin","/wechat/userBindLogin","/wechat/userBindGo","/wechat/userBind","/wechat/userUnBind","/weChatLogin","/weChatLogin.html","/indexV2").permitAll().antMatchers("/static/**").permitAll() // 不拦截静态资源.antMatchers("/views/**").permitAll() // 不拦截静态资源.antMatchers("/script/**").hasAuthority("ROLE_SuperPermission").antMatchers("/**").fullyAuthenticated()// 需要身份认证.and()// 登出后根据用户读取登出页面.logout().logoutUrl("/logOut") // 配置登出请求路径.invalidateHttpSession(true).and().headers().frameOptions().sameOrigin().and().rememberMe().tokenRepository(tokenRepository()).tokenValiditySeconds(3600) // Token过期时间为一个小时.and().csrf().disable() // 注销行为任意访问.headers()// 增加csp防xss攻击    frame-ancestors 针对frame的加载策略     default-src 针对默认加载策略 object-src 针对插件的加载策略.contentSecurityPolicy("frame-ancestors 'self'; default-src 'self' 'unsafe-inline' 'unsafe-eval' *.aliyuncs.com *.baidu.com *.bdimg.com ;object-src 'self'");}
}

1、configure分别配置两种登录验证方式,用户名和密码登陆使用userDetailsService方法返回的是带有用户名和密码的token,而authenticationProvider方法返回的是含有微信openid的自定义token,分别根据自己的验证逻辑来实现登录验证。

public void configure(AuthenticationManagerBuilder auth) throws Exception {//用户名和密码登陆auth.userDetailsService(customUserService()).passwordEncoder(new BCryptPasswordEncoder());//微信openid登陆auth.authenticationProvider(weChatAuthenticationProvider());}

2、分别定义两个拦截器,各自定义好需要拦截的登录url,并分别处理登录验证逻辑:

  • CustomAuthenticationFilter 拦截url:"/user/login"

  • WeChatAuthenticationFilter 拦截url:"/wechat/weChatLogin"

这两个url都在两个拦截器中有定义。

WeChatAuthenticationFilter wechatFilter = weChatAuthenticationFilter();CustomAuthenticationFilter customFilter = customAuthenticationFilter();ValidateCodeFilter validateCodeFilter = new ValidateCodeFilter();validateCodeFilter.setAuthenticationFailureHandler(myAuthenticationFailureHandler);// http.httpBasic()    //httpBasic登录 BasicAuthenticationFilter// 必须在注册之后的过滤器之间才能安插过滤器http.addFilterBefore(filter, UsernamePasswordAuthenticationFilter.class).addFilterBefore(wechatFilter, UsernamePasswordAuthenticationFilter.class).addFilterBefore(customFilter, UsernamePasswordAuthenticationFilter.class).addFilterAfter(validateCodeFilter, HttpMethodFilter.class)//表单登录,loginPage为登录请求的url,loginProcessingUrl为表单登录处理的URL.formLogin().loginPage(loginPage)// 登录需要经过的url请求.loginProcessingUrl("/user/login").loginProcessingUrl("/wechat/weChatLogin")

3、两个拦截器分别实现了自己的登陆成功和失败的处理逻辑

/*** 添加微信openid登陆验证的过滤器*/
@Bean
public WeChatAuthenticationFilter weChatAuthenticationFilter() throws Exception {WeChatAuthenticationFilter filter = new WeChatAuthenticationFilter();filter.setAuthenticationManager(authenticationManagerBean());filter.setAuthenticationSuccessHandler(wxAuthenticationnSuccessHandler);filter.setAuthenticationFailureHandler(wxAuthenticationFailureHandler);return filter;
}/*** 添加用户名和密码登陆验证的过滤器*/
@Bean
public CustomAuthenticationFilter customAuthenticationFilter() throws Exception {CustomAuthenticationFilter filter = new CustomAuthenticationFilter();filter.setAuthenticationManager(authenticationManagerBean());filter.setAuthenticationSuccessHandler(myAuthenticationSuccessHandler);filter.setAuthenticationFailureHandler(myAuthenticationFailureHandler);return filter;
}

五、自定义token

1、用户名和密码验证的token,需要账号密码作为验证

/*** @author: xxm* @description:用户名和密码验证的token*/
public class CustomAuthenticationToken extends UsernamePasswordAuthenticationToken {/****/private static final long serialVersionUID = -1076492615339314113L;public CustomAuthenticationToken(Object principal, Object credentials) {super(principal, credentials);}public CustomAuthenticationToken(Object principal, Object credentials,Collection<? extends GrantedAuthority> authorities) {super(principal, credentials, authorities);}
}

2、微信验证的token,只需要一个openid作为验证即可

/*** @author: xxm* @description:微信验证的token`*/
public class WeChatAuthenticationToken extends UsernamePasswordAuthenticationToken {private static final long serialVersionUID = -6231962326068951783L;public WeChatAuthenticationToken(Object principal) {super(principal, "");}public WeChatAuthenticationToken(Object principal, Collection<? extends GrantedAuthority> authorities) {super(principal, "", authorities);}}

六、自定义拦截器

1、用户名和密码登陆验证的过滤器,重写了拦截的请求URL,并定义好用户名、密码的参数名称,从请求中获取到用户名、密码,生成CustomAuthenticationToken

拦截器中生成的CustomAuthenticationToken,账号和密码是从前台传过来,它将会和UserDetailsService中返回的CustomAuthenticationToken的账号密码进行对比验证,账号密码是否正确。(UserDetailsService中返回的CustomAuthenticationToken的账号密码是从数据库查出来的)

/*** @author: xxm* @description:用户名和密码登陆验证的过滤器*/
public class CustomAuthenticationFilter extends AbstractAuthenticationProcessingFilter {public static final String SPRING_SECURITY_FORM_USERNAME_KEY = "username";public static final String SPRING_SECURITY_FORM_PASSWORD_KEY = "password";private String usernameParameter = SPRING_SECURITY_FORM_USERNAME_KEY;private String passwordParameter = SPRING_SECURITY_FORM_PASSWORD_KEY;private boolean postOnly = true;public CustomAuthenticationFilter() {//父类中定义了拦截的请求URL,/login的post请求,直接使用这个配置,也可以自己重写super("/user/login");}@Overridepublic Authentication attemptAuthentication(HttpServletRequest request,HttpServletResponse response) throws AuthenticationException {if (postOnly && !request.getMethod().equals("POST")) {throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());}String username = obtainUsername(request);String password = obtainPassword(request);if (username == null) {username = "";}if (password == null) {password = "";}username = username.trim();CustomAuthenticationToken authRequest = new CustomAuthenticationToken(username, password);// Allow subclasses to set the "details" propertysetDetails(request,authRequest);return this.getAuthenticationManager().authenticate(authRequest);}protected String obtainPassword(HttpServletRequest request) {String password =request.getParameter(passwordParameter);return password == null ? "" : password;}/*** Enables subclasses to override the composition of the username, such as by* including additional values and a separator.** @param request so that request attributes can be retrieved** @return the username that will be presented in the <code>Authentication</code>* request token to the <code>AuthenticationManager</code>*/protected String obtainUsername(HttpServletRequest request) {String username =request.getParameter(usernameParameter);return username == null ? "" : username;}protected void setDetails(HttpServletRequest request,UsernamePasswordAuthenticationToken authRequest) {authRequest.setDetails(authenticationDetailsSource.buildDetails(request));}
}

2、微信openid登陆验证的过滤器,重写了拦截的请求URL,并定义好openid的参数名称,从请求中获取到openid,生成WeChatAuthenticationToken

拦截器中生成的WeChatAuthenticationToken,openid是从前台传过来,它将会传递给WeChatAuthenticationProvider,并在该类中验证微信授权openid是否有效(根据openid查询数据库中是否关联用户即可)。

/*** @author: xxm* @description:微信openid登陆验证的过滤器*/
public class WeChatAuthenticationFilter extends AbstractAuthenticationProcessingFilter {private String openidParameter = "openid";public WeChatAuthenticationFilter() {super("/wechat/weChatLogin");//super.setAuthenticationFailureHandler(new MyAuthenticationFailureHandler());}/*** {@inheritDoc}*/@Overridepublic Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)throws AuthenticationException {if (!request.getMethod().equals(HttpMethod.GET.name())) {throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());}String openid = obtainOpenid(request);if (openid == null || openid.length() == 0) {throw new BadCredentialsException("uid or openid is null.");}WeChatAuthenticationToken authRequest = new WeChatAuthenticationToken(openid);authRequest.setDetails(authenticationDetailsSource.buildDetails(request));return this.getAuthenticationManager().authenticate(authRequest);}protected String obtainOpenid(HttpServletRequest request) {String openid = request.getParameter(this.openidParameter);return openid == null ? "" : openid.trim();}}

七、自定义UserDetailsService

用户、密码登录采用了该种方式,从数据库查询出用户信息,并且查询出权限,返回带有权限的用户信息

/*** @author xxm* 定义UserDetailsService 接口*/
@Service
public class CustomUserServiceImpl implements UserDetailsService {@AutowiredUserControllerClient userControllerClient;// 授权过程@Override/** 根据数据库获得用户信息,并且查询出权限,返回带有权限的用户信息。 */public UserDetails loadUserByUsername(String username) {SysUser user = userControllerClient.getUserInfoByLoginName(username);if (user != null) {HttpServletRequest request =((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();HttpSession session = request.getSession();session.setAttribute("username", username);List<String> permissionCodess = userControllerClient.findPermissionByAdminUserName(username);List<GrantedAuthority> grantedAuthorities = new ArrayList<>();for (String permissionCode : permissionCodess) {if (permissionCode != null && permissionCode != "") {GrantedAuthority grantedAuthority =new SimpleGrantedAuthority(permissionCode);grantedAuthorities.add(grantedAuthority);}}// 返回带有权限的userreturn new User(user.getUsername(), user.getPassword(), grantedAuthorities);} else {throw new UsernameNotFoundException("admin: " + username + " do not exist!");}}
}

八、自定义Provider

微信登录采用了该种方式,根据WeChatAuthenticationFilter 传过来的token信息获取到openid,并根据openid查询微信关联账户,完成验证。

/*** @author: xxm* @description:* @date: 2021/3/11 16:07*/
public class WeChatAuthenticationProvider implements AuthenticationProvider {@AutowiredUserWeChatClient userWeChatClient;@AutowiredUserControllerClient userControllerClient;@Overridepublic Authentication authenticate(Authentication authentication) throws AuthenticationException {if (authentication.isAuthenticated()) {return authentication;}//获取过滤器封装的token信息WeChatAuthenticationToken authenticationToken = (WeChatAuthenticationToken) authentication;String openid = (String)authenticationToken.getPrincipal();SysUser user = null;UserWeChatDto uwcDto = new UserWeChatDto();uwcDto.setOpenId(openid);List<UserWeChatDto> uwcList = userWeChatClient.getListByParam(uwcDto);if (null != uwcList && uwcList.size()==1) {UserWeChatDto userWeChatDto = uwcList.get(0);//微信账号已经与网站账号关联//根据用户id查询用户user = userControllerClient.getUserById(userWeChatDto.getUserId());//存放sessionHttpServletRequest request =((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();HttpSession session = request.getSession();session.setAttribute("username", user.getUsername());} else {//微信账号没有关联网站账号throw new BadCredentialsException("微信授权openid无效,请重新登陆");}
//        不通过if (user == null) {throw new BadCredentialsException("微信授权openid无效,请重新登陆");}// 根用户拥有全部的权限List<String> permissionCodess = userControllerClient.findPermissionByAdminUserName(user.getUsername());List<GrantedAuthority> authorities = new ArrayList<>();for (String permissionCode : permissionCodess) {if (permissionCode != null && permissionCode != "") {GrantedAuthority grantedAuthority =new SimpleGrantedAuthority(permissionCode);authorities.add(grantedAuthority);}}WeChatAuthenticationToken authenticationResult = new WeChatAuthenticationToken(openid, authorities);return authenticationResult;}@Overridepublic boolean supports(Class<?> authentication) {return WeChatAuthenticationToken.class.isAssignableFrom(authentication);}}

九、自定义Handler

根据验证成功与失败返回相应数据和操作

/**** @author: xxm* 功能描述: 微信登陆成功后操作* @param: * @return: */
@Service
public class WxAuthenticationnSuccessHandler implements AuthenticationSuccessHandler {@Overridepublic void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication)throws IOException, ServletException {response.sendRedirect("/index.html");}
}
/**
*
* @author: xxm
* 功能描述: 微信登录验证失败操作
* @param: 
* @return: 
*/
@Service
public class WxAuthenticationFailureHandler implements AuthenticationFailureHandler {
private ObjectMapper objectMapper = new ObjectMapper();@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {// 返回json数据Map result = new HashMap();result.put("wx_success", false);result.put("codeRtn", false);// 错误信息result.put("errorMsg", exception.getMessage());String json = objectMapper.writeValueAsString(result);response.setContentType("text/json;charset=utf-8");response.getWriter().write(json);
}
}

结束

从准备工作的资料,加上本文的相关代码,就可以实现账号用户名+微信网页授权登录集成在Spring Security。

作者:小苹果1357

来源:blog.csdn.net/xue317378914/article/

details/115250414

 
往期推荐:
Java 实现word、excel、ppt、txt等办公文件在线预览功能!这个系统被吹爆了,Nginx 可视化配置监控一条龙快速搞定!ChatGPT 详细介绍:原理、应用、如何试用,统统搞定!如何搭建一台永久运行的个人服务器?SpringBoot 实现动态配置及项目打包部署上线SpringBoot 调用外部接口的三种方式11.8K Star 数!超美观强的Nginx 可视化管理界面Spring Boot 操作 Redis 的各种实现

28072bf6f2e13b19141e6dceedb1bc69.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/56258.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

CnOpenDataA股上市公司交易所监管措施数据

一、数据简介 证券市场监管是指证券管理机关运用法律的、经济的以及必要的行政手段&#xff0c;对证券的募集、发行、交易等行为以及证券投资中介机构的行为进行监督与管理。 我国《证券交易所管理办法》第十二条规定&#xff0c;证券交易所应当按照章程、协议以及业务规则的规…

四套上市公司家族、股权关联数据助力公司金融深度研究

四套上市公司家族关联数据&#xff1a;家族企业在我国上市公司中占有庞大比例&#xff0c;已经成为推动我国经济高质量发展的动力之一。家族企业作为民营经济的重要组成部分&#xff0c;在我国的GDP增长、税收以及就业等方面做出的贡献不容小觑。上市公司家族企业的关联、融资、…

新手练习2:人物模型多边形建模流程图解

一&#xff0c;核心布线篇 1&#xff0c;打开Blender&#xff0c;新建一个“常规”文件&#xff0c;按Tab键对立方体进行调整&#xff0c; 2&#xff0c; 按 ~ 键切换视图&#xff0c;按快捷键1切换顶点&#xff0c;选择左边顶点删除&#xff0c;对其添加镜像修改器&#xff0…

CI 与 CD 持续集成与交付(2)

在CI 与 CD持续集成与交付&#xff08;1&#xff09;http://t.csdn.cn/TF3zC 里面简述了要持续集成要哪些基本工具和和工具安装使用&#xff0c;下面我用实验验证 jenkins 怎么去集成这3大工具的使用 第一步先下载Jenkins的war 包 java -jar jenkins.war 启动 Jenkins web应…

快讯 | 低成本开源聊天机器人Vicuna;首批因 AI 失业的人出现

一分钟速览新闻点 首批因 AI 失业的人出现&#xff0c;某游戏公司裁掉半数原画师西安交大开发出基于多功能智能皮肤的自适应变色系统术锐机器人完成数亿元C3轮融资&#xff0c;手术机器人成资本香饽饽谷歌称其 AI 超算系统比英伟达 A100 更快、更节能ChatGPT已经恢复Plus订阅服…

服装连锁店管理系统设计与实现

开发工具(eclipse/idea/vscode等)&#xff1a; 数据库(sqlite/mysql/sqlserver等)&#xff1a; 功能模块(请用文字描述&#xff0c;至少200字)&#xff1a;

基于SSM 技术的服装店管理系统

随着各个服装公司的发展&#xff0c;以及现在的客流量的增加&#xff0c;很多的服装公司的内容管理系统出现了很多的问题&#xff0c;比如说系统的服务不全面&#xff0c;系统高峰时期出现卡顿等一些体验不是十分好的现象。本次毕业设计从服装行业的本身需求出发,服装公司内部的…

基于SSMEasyUI的西服门店管理系统-java门店管理服装管理系统

基于SSM&EasyUI的西服门店管理系统-java门店管理服装管理系统 1.包含源程序&#xff0c;数据库脚本。代码和数据库脚本都有详细注释。2.课题设计仅供参考学习使用&#xff0c;可以在此基础上进行扩展完善开发环境&#xff1a;Eclipse ,MYSQL,JDK1.7,Tomcat 7涉及技术点&…

服装店小程序商城开发,有效帮助门店增加私域流量,提升门店销量

文/江苏微微小程序开发 线下服装店普遍遭遇获客难的问题&#xff0c;主要原因是店铺曝光不足&#xff0c;受限于地理位置&#xff0c;和线上电商冲击。 开发服装小程序商城&#xff0c;可以很好地扩大店铺曝光半径&#xff0c;利用小程序中的附近的小程序功能&#xff0c;服装…

服装租赁与买卖系统设计

其他项目&#xff0c;点击作者主页 目录 1 系统简介 2 系统相关技术 2.1 Java 2.2 MySql数据库 2.3 MyEclipse技术 2. 4 Tomcat服务器 3 需求分析 3.1 系统可行性分析 3.1.1 技术可行性分析 3.1.2 经济可行性分析 3.1.3 社会可行性 3.2 系统功能需求分析 4 系统…

服装零售软件大合集,你想知道的都在这里!

最近总是听到服装零售店老板的诉苦&#xff1a; 1、一年四季更换&#xff0c;服装零售店面临着换季更替&#xff0c;潮流迭代&#xff0c;于是也承担着巨额的库存成本&#xff0c;加上当前运输成本不断上涨&#xff0c;店铺支出压力越来越大&#xff0c;服装零售店的库存消化能…

推荐一款可以设计衣服的软件?零基础小白不可错过的服装设计工具

推荐一款可以设计衣服的手机软件&#xff1f;服装设计中设计绘画是个很重要的步骤&#xff0c;服装画主要是表达设计师所设计的时装整体效果及感觉&#xff0c;通过设计来表达设计师的设计理念及风格&#xff0c;其中包括对衣服的设计、面料、廓形等等的表达所以对于服装设计的…

衣橱管理APP——《衣橱管家》页面设计

目录 一、界面总体设计二、详细界面说明1.登录注册2.日历3.智能推荐4.我的5.衣橱6.时尚 三、附录 一、界面总体设计 《衣橱管家》有五大核心模块&#xff1a;衣橱管理、智能穿搭推荐、智能购买推荐、时尚社区、日常穿搭记录&#xff1b;界面设计将围绕这五大核心模块与登录注册…

服装店商家不离手的十大服装进销存管理软件,功能大对比

随着管理成本的提高&#xff0c;加上信息技术的发展&#xff0c;各行各业都要求应用专业的技术软件来提高管理效率&#xff0c;中小商户也不例外。 进销存软件是时代的产物&#xff0c;也是中小商户们想要做大做强生意的必然要求。然而市面上的进销存软件高达上百款&#xff0…

中小型服装店如何选择管理软件?

中小型服装店在发展中逐渐建立属于门店的会员管理、员工管理、商品管理体系&#xff0c;使用管理软件来提高门店经营效率&#xff0c;那么选择服装店管理软件要看哪些方面? 小编给大家一些中小型服装店选择软件时考虑的方面&#xff1a; 软件价格。中小型门店服装店规模小&…

基于C#的服装店进销存管理系统设计与实现

目 录 第一章 前言 1 1.1 选题背景 1 1.2 毕业论文的主要内容 1 第二章 服装连锁管理系统开发环境 3 2.1 开发环境选择 3 2.2 代码管理工具 3 2.3 项目代码命名空间规划 3 2.4 系统结构分析 4 第三章 服装连锁管理系统数据库设计 6 3.1 数据库的选择 6 3.2 系统数据库的设计 6 …

服装店如何建立系统的会员制度?

服装店要在竞争中立于不败之地&#xff0c;就要让自己的经营管理适应现代竞争的需要。服装店的核心就是会员&#xff0c;要不断开发新顾客&#xff0c;并维护老顾客。使单个顾客创造的利润最大化&#xff0c;并且能够长期循环&#xff0c;是服装店老板最想看到的。 会员制&…

服装实体店运营需要的所有软件,合集在此!(建议收藏)实体店运营 实体店运营干货 实体店运营全流程所需系统推荐

随着信息化普及程度越来越高&#xff0c;各行各业的运转速度都在加快&#xff0c;做生意的老板们也开始发现&#xff0c;单靠以前的人工管理已经完全不够用了。 尤其是服装实体店&#xff0c;款式分类多&#xff0c;库存又容易挤压&#xff0c;更加需要有科学的手段去管控日常的…

Python-裁判文书网

开门见山&#xff0c;直入主题&#xff0c;好久没更新了&#xff0c;搞一搞&#xff0c; 就来个 --裁判文书网 fiddler抓包: 打开fiddler 然后访问裁判文书网并选择筛选条件 整理下fiddler 删除一些干扰的链接&#xff0c;如&#xff1a;图片&#xff0c;css等等。 然后来分…

裁判文书网

裁判文书网 爬取动态加载的数据&#xff08;js加密eval,jsfuck &#xff09; 分析网页 1.打开首页 [外链图片转存失败(img-sFgp9WYn-1566049211688)(E:\CSDN 博客\裁判文书网\首页.png)] 从各个标签入手&#xff0c;当点击其中一个分类&#xff0c;刑事案件的时候&#xf…