Spring Boot安全管理

本项目内容出自书籍《SpringBoot企业级开发教程》中第七章的项目内容,有兴趣的同学可以网上搜索一下,这里仅仅作为项目记录,将不会进行代码解释

sql数据库

# 选择使用数据库
USE springbootdata;
# 创建表t_customer并插入相关数据
DROP TABLE IF EXISTS `t_customer`;
CREATE TABLE `t_customer` (`id` int(20) NOT NULL AUTO_INCREMENT,`username` varchar(200) DEFAULT NULL,`password` varchar(200) DEFAULT NULL,`valid` tinyint(1) NOT NULL DEFAULT '1',PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
INSERT INTO `t_customer` VALUES ('1', 'shitou', '$2a$10$5ooQI8dir8jv0/gCa1Six.GpzAdIPf6pMqdminZ/3ijYzivCyPlfK', '1');
INSERT INTO `t_customer` VALUES ('2', '李四', '$2a$10$5ooQI8dir8jv0/gCa1Six.GpzAdIPf6pMqdminZ/3ijYzivCyPlfK', '1');
# 创建表t_authority并插入相关数据
DROP TABLE IF EXISTS `t_authority`;
CREATE TABLE `t_authority` (`id` int(20) NOT NULL AUTO_INCREMENT,`authority` varchar(20) DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
INSERT INTO `t_authority` VALUES ('1', 'ROLE_common');
INSERT INTO `t_authority` VALUES ('2', 'ROLE_vip');
# 创建表t_customer_authority并插入相关数据
DROP TABLE IF EXISTS `t_customer_authority`;
CREATE TABLE `t_customer_authority` (`id` int(20) NOT NULL AUTO_INCREMENT,`customer_id` int(20) DEFAULT NULL,`authority_id` int(20) DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
INSERT INTO `t_customer_authority` VALUES ('1', '1', '1');
INSERT INTO `t_customer_authority` VALUES ('2', '2', '2');
# 记住我功能中创建持久化Token存储的数据表
create table persistent_logins (username varchar(64) not null,series varchar(64) primary key,token varchar(64) not null,last_used timestamp not null);

pom.xml

<dependencies><!-- Security与Thymeleaf整合实现前端页面安全访问控制 --><dependency><groupId>org.thymeleaf.extras</groupId><artifactId>thymeleaf-extras-springsecurity5</artifactId></dependency><!-- Redis缓存启动器--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><!-- Spring Security提供的安全管理依赖启动器 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!-- JDBC数据库连接启动器 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId></dependency><!-- MySQL数据连接驱动 --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><scope>runtime</scope></dependency><!-- Spring Data JPA操作数据库  --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build>

application.properties

# MySQL数据库连接配置
spring.datasource.url=jdbc:mysql://localhost:3306/springbootdata?serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=root# Redis服务器地址
spring.redis.host=127.0.0.1
# Redis服务器连接端口
spring.redis.port=6379
# Redis服务器连接密码(默认为空)
spring.redis.password=# thymeleaf页面缓存设置(默认为true),开发中方便调试应设置为false,上线稳定后应保持默认true
spring.thymeleaf.cache=false

实体类:

Customer

package com.demo.domain;import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import java.io.Serializable;@Entity(name = "t_customer")
public class Customer implements Serializable {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Integer id;private String username;private String password;(省略getter、setter、toString方法)

Authority

package com.demo.domain;import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import java.io.Serializable;@Entity(name = "t_authority ")
public class Authority implements Serializable {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Integer id;private String authority ;(省略getter、setter、toString方法)

AuthorityRespository

package com.demo.repository;import com.demo.domain.Authority;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;import java.util.List;public interface AuthorityRepository extends JpaRepository<Authority,Integer> {@Query(value = "select a.* from t_customer c,t_authority a,t_customer_authority ca where ca.customer_id=c.id and ca.authority_id=a.id and c.username =?1",nativeQuery = true)public List<Authority> findAuthoritiesByUsername(String username);}

CustomerRepository

package com.demo.repository;import com.demo.domain.Customer;
import org.springframework.data.jpa.repository.JpaRepository;public interface CustomerRepository extends JpaRepository<Customer,Integer> {Customer findByUsername(String username);
}

CustomerService

package com.demo.service;import com.demo.domain.Customer;
import com.demo.domain.Authority;
import com.demo.repository.CustomerRepository;
import com.demo.repository.AuthorityRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;import java.util.List;@Service
public class CustomerService {@Autowiredprivate CustomerRepository customerRepository;@Autowiredprivate AuthorityRepository authorityRepository;@Autowiredprivate RedisTemplate redisTemplate;// 业务控制:使用唯一用户名查询用户信息public Customer getCustomer(String username){Customer customer=null;Object o = redisTemplate.opsForValue().get("customer_"+username);if(o!=null){customer=(Customer)o;}else {customer = customerRepository.findByUsername(username);if(customer!=null){redisTemplate.opsForValue().set("customer_"+username,customer);}}return customer;}// 业务控制:使用唯一用户名查询用户权限public List<Authority> getCustomerAuthority(String username){List<Authority> authorities=null;Object o = redisTemplate.opsForValue().get("authorities_"+username);if(o!=null){authorities=(List<Authority>)o;}else {authorities=authorityRepository.findAuthoritiesByUsername(username);if(authorities.size()>0){redisTemplate.opsForValue().set("authorities_"+username,authorities);}}return authorities;}
}

UserDetailsServiceImpl

package com.demo.service;import com.demo.domain.Authority;
import com.demo.domain.Customer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.*;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;@Service
public class UserDetailsServiceImpl implements UserDetailsService {@Autowiredprivate CustomerService customerService;@Overridepublic UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {// 通过业务方法获取用户及权限信息Customer customer = customerService.getCustomer(s);List<Authority> authorities = customerService.getCustomerAuthority(s);// 对用户权限进行封装List<SimpleGrantedAuthority> list = authorities.stream().map(authority -> new SimpleGrantedAuthority(authority.getAuthority())).collect(Collectors.toList());// 返回封装的UserDetails用户详情类if(customer!=null){UserDetails userDetails= new User(customer.getUsername(),customer.getPassword(),list) ;return userDetails;} else {// 如果查询的用户不存在(用户名不存在),必须抛出此异常throw new UsernameNotFoundException("当前用户不存在!");}
//        User user = new User(customer.getUsername(), customer.getPassword(), list);
//        return user;}
}

SecurityConfig

package com.demo.config;import com.demo.service.UserDetailsServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;import javax.sql.DataSource;@EnableWebSecurity  //开启MVC Security安全支持
public class SecurityConfig extends WebSecurityConfigurerAdapter {@Autowired//3.private UserDetailsServiceImpl userDetailsService;@Autowiredprivate DataSource dataSource;//书中7-3到7-4内容@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception{//密码需要设置编码器BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();//1.使用内存用户信息,作为测试使用
//        auth.inMemoryAuthentication().passwordEncoder(encoder)
//                .withUser("shitou").password(encoder.encode("123456")).roles("common")
//                .and()
//                .withUser("admin").password(encoder.encode("admin")).roles("vip");
//        //2.使用JDBC进行身份验证
//        String userSQL = "select username,password,valid from t_customer where username = ?";
//        String authoritySQL = "select c.username,a.authority " +
//                "from t_customer c,t_authority a,t_customer_authority ca " +
//                "where ca.customer_id = c.id and ca.authority_id = a.id and c.username = ?";
//        auth.jdbcAuthentication().passwordEncoder(encoder)
//                .dataSource(dataSource)
//                .usersByUsernameQuery(userSQL)
//                .authoritiesByUsernameQuery(authoritySQL);//3.使用UserDetailsService进行身份认证auth.userDetailsService(userDetailsService).passwordEncoder(encoder);}@Overrideprotected void configure(HttpSecurity http) throws Exception{http.authorizeRequests().antMatchers("/").permitAll()//需要对static文件夹下静态资源进行统一放行.antMatchers("/login/**").permitAll().antMatchers("/detail/common/**").hasRole("common").antMatchers("/detail/vip/**").hasRole("vip").anyRequest().authenticated().and().formLogin();//自定义用户登陆控制http.formLogin().loginPage("/userLogin").permitAll().usernameParameter("name").passwordParameter("pwd").defaultSuccessUrl("/").failureUrl("/userLogin?error");//自定义用户退出控制http.logout().logoutUrl("/mylogout").logoutSuccessUrl("/");//定制Remember-me记住我功能http.rememberMe().rememberMeParameter("rememberme").tokenValiditySeconds(200)//对Cookie信息进行持久化管理.tokenRepository(tokenRepository());//可以关闭Spring Security默认开启的CSRF防护功能
//        http.csrf().disable();}@Beanpublic JdbcTokenRepositoryImpl tokenRepository(){JdbcTokenRepositoryImpl jr = new JdbcTokenRepositoryImpl();jr.setDataSource(dataSource);return jr;}
}

CSRFController

package com.demo.controller;import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;import javax.servlet.http.HttpServletRequest;@Controller
public class CSRFController {//向用户修改页跳转@GetMapping("/toUpdate")public String toUpdate(){return "/csrf/csrfTest";}//用户修改提交处理@ResponseBody@PostMapping(value = "/updateUser")public String updateUser(@RequestParam String username, @RequestParam String password, HttpServletRequest request){System.out.println(username);System.out.println(password);String csrf_token = request.getParameter("_csrf");System.out.println(csrf_token);return "OK";}
}

FileController

package com.demo.controller;import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.context.SecurityContextImpl;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.ResponseBody;import javax.servlet.http.HttpSession;
import java.util.Enumeration;@Controller
public class FileController {//影片详情页@GetMapping("/detail/{type}/{path}")public String toDetail(@PathVariable("type") String type,@PathVariable("path") String path){return "detail/"+type+"/"+path;}@GetMapping("/userLogin")public String toLoginPage(){return "login/login";}@GetMapping("/getuserBySession")@ResponseBodypublic void getUser(HttpSession session){//从当前HttpSession获取绑定到此会话的所有对象名称Enumeration<String> names = session.getAttributeNames();while (names.hasMoreElements()){//获取httpSession中会话名称String element = names.nextElement();//获取HttpSession中的应用上下文SecurityContextImpl attribute = (SecurityContextImpl) session.getAttribute(element);System.out.println("element:"+element);System.out.println("attribute:"+attribute);//获取用户相关信息Authentication authentication = attribute.getAuthentication();UserDetails principal = (UserDetails) authentication .getPrincipal();System.out.println(principal);System.out.println("username:"+principal.getUsername());}}@GetMapping("/getUserByContext")@ResponseBodypublic void getUser2(){SecurityContext context = SecurityContextHolder.getContext();//获取用户相关信息Authentication authentication = context.getAuthentication();UserDetails principal = (UserDetails) authentication.getPrincipal();System.out.println(principal.getUsername());}
}

index.html

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity5">>
<head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>影视直播厅</title>
</head>
<body>
<h1 align="center">欢迎进入电影网站首页</h1>
<div sec:authorize="isAnonymous()"><h2 align="center">游客您好,如果想查看电影<a th:href="@{/userLogin}">请登录</a></h2>
</div>
<div sec:authorize="isAuthenticated()"><h2 align="center"><span sec:authentication="name" style="color: #007bff"></span>您好,您的用户权限为<span sec:authentication="principal.authorities" style="color:darkkhaki"></span>,您有权观看以下电影</h2><form th:action="@{/mylogout}" method="post"><input th:type="submit" th:value="注销" /></form>
</div>
<hr>
<h3>普通电影</h3>
<ul><li><a th:href="@{/detail/common/1}">我不是药神</a></li><li><a th:href="@{/detail/common/2}">夏洛特烦恼</a></li>
</ul>
<h3>VIP专享</h3>
<ul><li><a th:href="@{/detail/vip/1}">速度与激情</a></li><li><a th:href="@{/detail/vip/2}">猩球崛起</a></li>
</ul>
</body>
</html>

自定义登陆login.html

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>用户登录界面</title><link th:href="@{/login/css/bootstrap.min.css}" rel="stylesheet"><link th:href="@{/login/css/signin.css}" rel="stylesheet">
</head>
<body class="text-center">
<form class="form-signin" th:action="@{/userLogin}" th:method="post" ><img class="mb-4" th:src="@{/login/img/login.jpg}" width="72px" height="72px"><h1 class="h3 mb-3 font-weight-normal">请登录</h1><!-- 用户登录错误信息提示框 --><div th:if="${param.error}"style="color: red;height: 40px;text-align: left;font-size: 1.1em"><img th:src="@{/login/img/loginError.jpg}" width="20px">用户名或密码错误,请重新登录!</div><input type="text" name="name" class="form-control"placeholder="用户名" required="" autofocus=""><input type="password" name="pwd" class="form-control"placeholder="密码" required=""><div class="checkbox mb-3"><label><input type="checkbox" name="rememberme">记住我</label></div><button class="btn btn-lg btn-primary btn-block" type="submit" >登录</button><p class="mt-5 mb-3 text-muted">Copyright© 2019-2020</p>
</form>
</body>
</html>

内容页

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>影片详情</title>
</head>
<body><a th:href="@{/}">返回</a><h1>我不是药神</h1><p style="width: 550px">简介:根据真实社会事件改编,一位不速之客的意外到访,打破了神油店老板程勇(徐峥 饰)的平凡人生,他从一个交不起房租的男性保健品商贩,一跃成为印度仿制药“格列宁”的独家代理商。收获巨额利润的他,生活剧烈变化,被病患们冠以“药神”的称号。但是,一场关于救赎的拉锯战也在波涛暗涌中慢慢展开……</p>
</body>
</html>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>影片详情</title>
</head>
<body><a th:href="@{/}">返回</a><h1>夏洛特烦恼</h1><p style="width: 550px">简介:《夏洛特烦恼》是开心麻花2012年首度推出的话剧,由闫非和彭大魔联合编剧、执导。2013、2014、2015年仍在上演。该作讲述了一个普通人在穿越重回到高中校园并实现了种种梦想的不可思议的经历……</p>
</body>
</html>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>影片详情</title>
</head>
<body><a th:href="@{/}">返回</a><h1>速度与激情</h1><p style="width: 550px">简介:《速度与激情》是罗伯·科恩等执导,于2001年至2017年范·迪塞尔、保罗·沃克(已故)、乔丹娜·布鲁斯特、米歇尔·罗德里格兹等主演的赛车题材的动作犯罪类电影,截至2018年,一共拍了八部。之后两部续集正式定档,《速度与激情9》和《速度与激情10》分别于2020年4月10日和2021年4月2日上映……</p>
</body>
</html>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>影片详情</title>
</head>
<body><a th:href="@{/}">返回</a><h1>猩球崛起</h1><p style="width: 550px">简介:《猩球崛起》是科幻片《人猿星球》的前传,由鲁伯特·瓦耶特执导,詹姆斯·弗兰科,汤姆·费尔顿,芙蕾达·平托,布莱恩·考克斯等主演。剧情主要讲述人猿进化为高级智慧生物、进而攻占地球之前的种种际遇,主题是带有警世性质的——人类疯狂的野心所产生的恶果。影片获得了第39届安妮奖最佳真人电影角色动画奖等奖项,同时获得了奥斯卡最佳特效奖提名,但很遗憾,并没有获奖……</p>
</body>
</html>

csrf.html

<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head><meta charset="UTF-8"><title>用户修改</title>
</head>
<body>
<div align="center"><form method="post" th:action="@{/updateUser}">
<!--      <input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}">-->用户名:<input type="text" name="username"/><br/>密  码:<input type="password" name="password"/><br/><button type="submit">修改</button></form>
</div>
</body>
</html>

至此整个项目完成

Spring Boot安全管理相关推荐

  1. Spring Boot安全管理—基于数据库的认证

    基于数据库的认证 1. 设计数据库表 首先设计一个基本的用户角色表,一共三张表,分别是用户表.角色表以及用户角色关联表. SET FOREIGN_KEY_CHECKS=0;-- ----------- ...

  2. 十、Spring Boot 安全管理(2)

    本章概要 基于数据库的认证 10.2 基于数据库的认证 在真实的项目中,用户的基本信息以及角色等都存储在数据库中,因此需要从数据库中获取数据进行认证和授权. 1. 设计数据表 用户表.角色表.用户角色 ...

  3. 《Spring Boot+Vue全栈开发实战》读书笔记

    写在前面 嗯,回家处理一些事,所以离职了,之前的公司用开源技术封装了一套自己的低代码平台,所以之前学的spring Boot之类的东西都忘了很多,蹭回家的闲暇时间复习下. 笔记整体以 Spring B ...

  4. Spring Boot+Vue全栈开发实战——花了一个礼拜读懂了这本书

    很幸运能够阅读王松老师的<Spring Boot+Vue全栈开发实战>这本书!之前也看过Spring Boot与Vue的相关知识,自己也会使用了Spring Boot+Vue进行开发项目. ...

  5. 读书笔记《Spring Boot+Vue全栈开发实战》(下)

    本书将带你全面了解Spring Boot基础与实践,带领读者一步步进入 Spring Boot 的世界. 前言 第九章 Spring Boot缓存 第十章 Spring Boot安全管理 第十一章 S ...

  6. spring boot shiro redis整合基于角色和权限的安全管理-Java编程

    一.概述 本博客主要讲解spring boot整合Apache的shiro框架,实现基于角色的安全访问控制或者基于权限的访问安全控制,其中还使用到分布式缓存redis进行用户认证信息的缓存,减少数据库 ...

  7. sm4 前后端 加密_这7个开源的Spring Boot前后端分离项目整理给你

    来源|公众号:江南一点雨 前后端分离已经开始逐渐走进各公司的技术栈,不少公司都已经切换到前后端分离开发技术栈上面了,因此建议技术人学习前后端分离开发以提升自身优势.同时,也整理了 7 个开源的 Spr ...

  8. 前后端分离项目_七个开源的 Spring Boot 前后端分离项目,一定要收藏

    来自公众号:江南一点雨 前后端分离已经在慢慢走进各公司的技术栈,根据松哥了解到的消息,不少公司都已经切换到这个技术栈上面了.即使贵司目前没有切换到这个技术栈上面,松哥也非常建议大家学习一下前后端分离开 ...

  9. Spring Boot 2.5.0 重新设计的spring.sql.init 配置有啥用?

    点击关注,赶紧上车 前几天Spring Boot 2.5.0发布了,其中提到了关于Datasource初始化机制的调整,有读者私信想了解这方面做了什么调整.那么今天就要详细说说这个重新设计的配置内容, ...

最新文章

  1. jupyter notebook 更改工作目录
  2. 谈谈你的GC调优思路?
  3. spark streaming 的 Job创建、调度、提交
  4. ssl提高组国庆模拟赛【2018.10.5】
  5. c语言自动突破,为你解决c语言源代码【突破方案】
  6. 知识图谱在美团推荐场景中的应用实践
  7. 【java笔记】Stream流(1)你知道什么叫Stream流吗?
  8. 【新手可看懂】ubuntu配置appium环境
  9. 音频分离Spleeter的安装
  10. Google发布了Google Sketchup,完全免费
  11. Luat合宙ESP32C3教程-点亮ST7735驱动1.8寸TFT液晶屏
  12. php storm官网,phpstorm官方版
  13. CentOS7如何设置屏幕不休眠
  14. 机器学习从入门到创业手记-处理数据的乐趣在于挖掘
  15. 光猫、路由器、交换机、wifi通俗释义
  16. 数据结构和算法学习网站
  17. Hbase shell过滤操作
  18. 进行范围查找的折半查找法
  19. 恒大法拉第汽车FF的Logo赏析
  20. 既然硕士毕业也去搞开发,那还去读研值吗?

热门文章

  1. c ajax 调用webservice,Asp.net Ajax WebService 实现循环引用(自定义JavascriptC
  2. 软件外包公司的入职须知
  3. 千耘农机导航的“星地一体”能力究竟是什么?
  4. 2021 - 辽宁省第二届大学生程序设计竞赛
  5. linux rmmod :remove ‘xxx.ko‘ :Function not implemented
  6. 输出一个浮点数,保留三位小数
  7. 思科6506恢复密码
  8. python画球轨迹图_python绘制铅球的运行轨迹代码分享
  9. Python基础之入门
  10. svn创建分支(branch/tag)出现“path”already exists