git 提交代码 到 gitee仓库指定文件夹中

一、创建一个空文件夹

二、将gitee仓库地址复制下来

三、在刚刚新建的空文件夹真打开 Git Bash Here

四、克隆 gitee 仓库

五、提交代码

将想要提交的拖到克隆下来的目录下面

六、执行指令

1. 执行 git add 文件名 (如果是git add . 表示当前目录下的所有内容),注意,add后要一个空格

1
git add 文件名

可能会出现如下报错,

则需要输入 git init 然后回车就好了

1
git init

然后再重新执行添加文件就可以了(注意,一定要将目录切换到仓库目录,负责执行命令时会报fatal: pathspec ‘hotel-demo’ did not match any files)

2. 执行git commit -m “注释的内容” ( 提交到本地仓库)

1
git commit -m "注释的内容"

3. 提交代码到 gitee

执行命令: git remote add origin 远程项目的 Https 地址

1
git remote add origin 远程项目的 Https 地址

可能有人会报如下错误(没有的话可以忽略)

解决:执行 git remote rm origin 删除关联的origin的远程库

1
git remote rm origin

然后再重新执行 git remote add origin 远程项目的 Https 地址即可

4. git push -u origin master ( 最后这一步就可以推送到自己的仓库了)

1
git push -u origin master 

完成 !!

Docker删除镜像是报错:Error response from daemon:conflict:unable to remove repository

Error response from daemon: conflict: unable to remove repository reference “nginx:latest” (must force) - container 50a3d44fa9aa is using its referenced image 605c77e624dd

翻译是:

    来自守护程序的错误响应:冲突:无法删除存储库引用“nginx:latest”(必须强制) - 容器 50a3d44fa9aa 正在使用其引用的映像 605c77e624dd  

错误原因是:

    因为在使用镜像的时候启动了容器,故得把前面使用的容器先给删除,才能继续删除镜像。

解决:

    直接将指令改为:docker rmi -f [镜像ID] 即可

    -f 强制删除

SpringSecurity微服务权限方案

image-20221109210902180

1.认证授权过程分析

微服务本质:

image-20221109210128213

image-20221109210445793

需求分析

image-20221109211556120

数据模型介绍:

image-20221109214015143

使用技术说明:

image-20221110144805581

搭建项目工程:

对应教程视频:25-尚硅谷-SpringSecurity-微服务权限案例-引入项目依赖_哔哩哔哩_bilibili

image-20221110145058838

image-20221110150906119

启动Redis和Nacos:

image-20221110180707351

编写common工具类:

对应教程视频:27-尚硅谷-SpringSecurity-微服务权限案例-编写common工具类_哔哩哔哩_bilibili

image-20221110184003848

编写security工具类:

对应教程视频:28-尚硅谷-SpringSecurity-微服务权限案例-编写security工具类_哔哩哔哩_bilibili

image-20221110205032587

2.1 密码处理工具类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
import atguigu.utils.utils.MD5;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;

/**
* @author : 其然乐衣Letitbe
* @date : 2022/11/10
*/
@Component
public class DefaultPasswordEncoder implements PasswordEncoder {

public DefaultPasswordEncoder() {
// 调用有参构造方法,传值 -1
this(-1);
}

public DefaultPasswordEncoder(int strength) {

}

/**
* 进行MD5加密
*/
@Override
public String encode(CharSequence charSequence) {
return MD5.encrypt(charSequence.toString());
}

/**
* 进行密码比对
* 比对一样的话返回 true,不一样的话返回false
* @param charSequence 加密后的密码
* @param encodedPassword 传入的密码
* @return
*/
@Override
public boolean matches(CharSequence charSequence, String encodedPassword) {
return encodedPassword.equals(MD5.encrypt(charSequence.toString()));
}
}

2.2 token操作工具类

先导入依赖:

1
2
3
4
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
</dependency>

使用jwt生成token代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
package com.atguigu.security.security;

import io.jsonwebtoken.CompressionCodecs;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.stereotype.Component;

import java.util.Date;

/**
* token工具类
* @author : 其然乐衣Letitbe
* @date : 2022/11/10
*/
@Component
public class TokenManager {

/**
* token有效时长
*/
private long tokenExpiration = 24 * 60 * 60 * 1000;
/**
* 编码密钥
*/
private String tokenSignKey = "123456";

/**
* 1. 使用 jwt 根据用户名生成token
*/
public String createToken(String username) {
String token = Jwts.builder()
// 设置主体信息
.setSubject(username)
// 设置有效时长
.setExpiration(new Date(System.currentTimeMillis() + tokenExpiration))
.signWith(SignatureAlgorithm.HS512, tokenSignKey).compressWith(CompressionCodecs.GZIP).compact();
return token;
}

/**
* 2. 根据token字符串得到用户信息
*/
public String getUserInfoFromToken(String token) {
String userinfo = Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token).getBody().getSubject();
return userinfo;
}

/**
* 3. 删除token
* 但是这个删除方法其实不需要我们写,因为token不需要咱们删,客户端不携带 token 就可以了
*/
public void removeToken(String token) {}
}

2.3 退出处理器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
import atguigu.utils.utils.R;
import atguigu.utils.utils.ResponseUtil;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.logout.LogoutHandler;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
* 退出处理器
* @author : 其然乐衣Letitbe
* @date : 2022/11/10
*/
public class TokenLogoutHandler implements LogoutHandler {

private TokenManager tokenManager;
private RedisTemplate redisTemplate;

public TokenLogoutHandler(TokenManager tokenManager, RedisTemplate redisTemplate) {
this.tokenManager = tokenManager;
this.redisTemplate = redisTemplate;
}

@Override
public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
// 1. 从header里面获取token
// 2. token不为空,移除token, 从redis删除token
String token = request.getHeader("token");
if (token != null) {
// 移除
tokenManager.removeToken(token);

// 从token获取用户名
String username = tokenManager.getUserInfoFromToken(token);
// key : username
redisTemplate.delete(username);
}
ResponseUtil.out(response, R.ok());
}
}

2.4 未授权统一处理类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import atguigu.utils.utils.R;
import atguigu.utils.utils.ResponseUtil;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
* 未授权统一处理类
* @author : 其然乐衣Letitbe
* @date : 2022/11/10
*/
public class UnauthEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
ResponseUtil.out(response, R.error());
}
}

编写security认证过滤器:

对应教程视频;29-尚硅谷-SpringSecurity-微服务权限案例-编写security认证过滤器_哔哩哔哩_bilibili

1. 认证的过滤器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
import atguigu.utils.utils.R;
import atguigu.utils.utils.ResponseUtil;
import com.atguigu.security.entity.SecurityUser;
import com.atguigu.security.entity.User;
import com.atguigu.security.security.TokenManager;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;

/**
* @author : 其然乐衣Letitbe
* @date : 2022/11/10
*/
public class TokenLoginFilter extends UsernamePasswordAuthenticationFilter {

private TokenManager tokenManager;
private RedisTemplate redisTemplate;
/**
* 由springsecurity封装的
*/
private AuthenticationManager authenticationManager;

public TokenLoginFilter(AuthenticationManager authenticationManager, TokenManager tokenManager, RedisTemplate redisTemplate) {
this.authenticationManager = authenticationManager;
this.tokenManager = tokenManager;
this.redisTemplate = redisTemplate;
// 设置为不仅仅是post提交
this.setPostOnly(false);
// 设置登录路径,且匹配post提交
this.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/admin/acl/login", "POST"));
}

/**
* 1. 获取表单提交用户名和密码
*/
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
// 获取表单提交数据
try {
User user = new ObjectMapper().readValue(request.getInputStream(), User.class);
return authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(user.getUsername(), user.getPassword(),
new ArrayList<>()));
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException();
}
}

/**
* 2. 认证成功时会调用的方法
*/
@Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult)
throws IOException, ServletException {
// 这个方法可以获取认证通过后的用户的信息,然后根据用户名生成token,再把它放到redis中
SecurityUser user = (SecurityUser) authResult.getPrincipal();
// 根据用户名生成token
String token = tokenManager.createToken(user.getCurrentUserInfo().getUsername());
// 把用户名称和用户权限列表放到redis
redisTemplate.opsForValue().set(user.getCurrentUserInfo().getUsername(), user.getPermissionValueList());
// 返回token
ResponseUtil.out(response, R.ok().data("token", token));
}

/**
* 3. 认证失败时会调用的方法
*/
@Override
protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed)
throws IOException, ServletException {
// 返回错误的提示
ResponseUtil.out(response, R.error());
}
}

2.授权过滤器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
import com.atguigu.security.security.TokenManager;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
* @author : 其然乐衣Letitbe
* @date : 2022/11/10
*/
public class TokenAuthFilter extends BasicAuthenticationFilter {
private TokenManager tokenManager;
private RedisTemplate redisTemplate;

public TokenAuthFilter(AuthenticationManager authenticationManager) {
super(authenticationManager);
this.tokenManager = tokenManager;
this.redisTemplate = redisTemplate;
}

@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
// 获取当前认证成功用户权限信息
UsernamePasswordAuthenticationToken authRequest = getAuthentication(request);
// 判断如果有权限信息,放到权限上下文中
if (authRequest != null) {
SecurityContextHolder.getContext().setAuthentication(authRequest);
}
chain.doFilter(request, response);
}

private UsernamePasswordAuthenticationToken getAuthentication(HttpServletRequest request) {
// 从header获取token
String token = request.getHeader("token");
if (token != null) {
// 从token获取用户
String username = tokenManager.getUserInfoFromToken(token);

//从redis获取对应权限列表
List<String> permissionValueList = (List<String>) redisTemplate.opsForValue().get(username);
Collection<GrantedAuthority> authorities = new ArrayList<>();
for ( String permissionValue : permissionValueList ) {
SimpleGrantedAuthority auth = new SimpleGrantedAuthority(permissionValue);
authorities.add(auth);
}
return new UsernamePasswordAuthenticationToken(username, token, authorities)
}
return null;
}
}

编写entity:

SecurityUser实体类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
* @author : 其然乐衣Letitbe
* @date : 2022/11/10
*/
@Data
@Slf4j
public class SecurityUser implements UserDetails {
//当前登录用户
private transient User currentUserInfo;
//当前权限
private List<String> permissionValueList;
public SecurityUser() {
}
public SecurityUser(User user) {
if (user != null) {
this.currentUserInfo = user;
}
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
Collection<GrantedAuthority> authorities = new ArrayList<>();
for(String permissionValue : permissionValueList) {
if(StringUtils.isEmpty(permissionValue)) {
continue;
}
SimpleGrantedAuthority authority = new
SimpleGrantedAuthority(permissionValue);
authorities.add(authority);
}
return authorities;
}
@Override
public String getPassword() {
return currentUserInfo.getPassword();
}
@Override
public String getUsername() {
return currentUserInfo.getUsername();
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
}

User用户实体类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
package com.atguigu.security.entity;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

import java.io.Serializable;

/**
* @author : 其然乐衣Letitbe
* @date : 2022/11/10
*/
@Data
@ApiModel(description = "用户实体类")
public class User implements Serializable {

private static final long serialVersionUID = 1L;

/**
* @ApiModelProperty用于swapper测试的
*/
@ApiModelProperty(value = "微信openid")
private String username;

@ApiModelProperty(value = "密码")
private String password;

@ApiModelProperty(value = "昵称")
private String nickName;

@ApiModelProperty(value = "用户头像")
private String salt;

@ApiModelProperty(value = "用户签名")
private String token;
}

整合网关和前端:

解决跨域配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.cors.reactive.CorsConfigurationSource;
import org.springframework.web.cors.reactive.CorsWebFilter;
import org.springframework.web.util.pattern.PathPatternParser;

/**
* @author : 其然乐衣Letitbe
* @date : 2022/11/11
*/
@Configuration
public class CorsConfig {

/**
* 解决跨域
*/
@Bean
public CorsWebFilter corsWebFilter() {
CorsConfiguration config = new CorsConfiguration();
// 表示该服务器允许任何类型的请求
config.addAllowedMethod("*");
// 允许任何域名来源的请求
config.addAllowedOrigin("*");
// 允许携带任何请求头
config.addAllowedHeader("*");

UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(new PathPatternParser());
// 表示所有路径都允许访问
source.registerCorsConfiguration("/**", config);

return new CorsWebFilter((CorsConfigurationSource) source);
}
}

配置文件:

application.properties:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 端口号
server.port=8222
# 服务名
spring.application.name=service-gateway
# nacos服务地址
spring.cloud.nacos.discovery.server-addr=222.177.66.230:8848
# 使服务发现路由
spring.cloud.gateway.discovery.locator.enabled=true

# 配置路由规则
spring.cloud.gateway.routes[0].id=service-acl
# 设置路由uri lb://注册服务名称
spring.cloud.gateway.routes[0].uri=lb://service-acl
# 具体路径规则
spring.cloud.gateway.routes[0].predicates= path=/*/acl/**

整合网关:

image-20221111165948445

云服务器上部署一个Springboot的web项目(图文讲解)

(PS:在部署之前,

1.你的虚拟机需要安装有jdk(这个Centos内部应该自带有,我的就是)和mysql(注意,如果你使用的数据库是8.0版本以上的,则需要安装mysql8.0以上的),没有安装到这两个的先自行去安装好

2.Linux安装好mysql后,去用sqlyog(或是Navicat或其他)连接你虚拟机的数据库

1.双击packege,打包项目。(注意,先鼠标选中Maven中的test然后跟着黄色箭头点击(让test被划掉),使得在打包项目的时候跳过test步骤,不然会执行项目的测试,从而可能改动数据库的原有数据)

2.找到打包好的项目的所在目录

3.(这一步有多种方法,我习惯这一种)

4.进入到Linux的相应目录,然后执行最后一条命令来启动springboot项目

5.启动成功,然后去根据虚拟机的ip端口去访问项目

(ps:如果访问超时,则需要去Linux关闭防火墙

1.首先切换回到 /root/bin目录下

2.执行命令:systemctl stop firewalld.service(关闭防火墙)

systemctl disable firewalld.service(关闭防火墙自动启动)

4.查看防火墙状态:systemctl status firewalld.service(查看防火墙服务状态)

看到这样就OK了:

然后再去浏览器访问,便不会超时了

另一种启动方式,启动过程中不会显示出日志信息,还可用命令将日志信息存到server.log中,或是存到自己创建的文件中也行

这是我保存的日志信息

(实体类没有写get和set方法若的祸啦)No serializer found for class com.example.domain

报错:
No serializer found for class com.example.domain.Men and no properties discovered to create Bean…

springboot中使用@RestController注解前台页面返回不到对象数据异常
异常信息
首页控制台会打印如下异常:

红色框里详细如下

No serializer found for class com.example.domain.Men and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: java.util.ArrayList[0])

原因:实体类没有写有对应的get()和set方法

解决

在实体类写上set() 和 get() 方法即可,并在其方法前要有public

service层传来的总是null?

开始写了四个接口,都没有问题,但是在写第五个接口时不行了,然后更可恶的是,前面的四个也都不行了!这这倒到底是怎么回事呢?接下来给大家分享我的情况:

报错如下图:在postman中访问接口出现报错

上图表示dataSectionService返回是空,问题原因是因为上头注入DataSectionService时定义成了static,切记是这样是不能的,否则就是会报异常,即便你的dao层的返回是正常的,但是在中间service层返回给controller层时是空的了。