docker pull nacos/nacos-server:1.2.0
docker run --env MODE=standalone --name nacos --restart=always -d -p 8848:8848 nacos/nacos-server:1.2.0
MODE=standalone
: 单机版--restart=always
: 开机启动-p 8848:8848
: 映射端口-d
: 创建一个守护式容器在后台运行heima-leadnews: 父工程, 统一管理项目依赖, 继承SpringBoot
新建数据库leadnews_user
表名称 | 说明 |
---|---|
ap_user | APP用户信息表 |
ap_user_fan | APP用户粉丝信息表 |
ap_user_follow | APP用户关注信息表 |
ap_user_realname | APP实名认证信息表 |
密码+salt
heima-leadnews-service
下创建模块heima-leadnews-user
@Slf4j
@SpringBootApplication
@EnableDiscoveryClient
@MapperScan("com.heima.user.mapper")
public class UserApplication {
public static void main(String[] args) {
SpringApplication.run(UserApplication.class, args);
log.info("项目启动成功");
}
}
server:
port: 51801
spring:
application:
name: leadnews-user
cloud:
nacos:
discovery:
server-addr: 192.168.174.133:8848
config:
server-addr: 192.168.174.133:8848
file-extension: yml
<configuration>
<property name="LOG_HOME" value="e:/logs"/>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%npattern>
<charset>utf8charset>
encoder>
appender>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/leadnews.%d{yyyy-MM-dd}.logfileNamePattern>
rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%npattern>
encoder>
appender>
<appender name="ASYNC" class="ch.qos.logback.classic.AsyncAppender">
<discardingThreshold>0discardingThreshold>
<queueSize>512queueSize>
<appender-ref ref="FILE"/>
appender>
<logger name="org.apache.ibatis.cache.decorators.LoggingCache" level="DEBUG" additivity="false">
<appender-ref ref="CONSOLE"/>
logger>
<logger name="org.springframework.boot" level="debug"/>
<root level="info">
<appender-ref ref="FILE"/>
<appender-ref ref="CONSOLE"/>
root>
configuration>
public ResponseResult login(LoginDto loginDto) {
// 1. 正常登录 用户名和密码
if(StringUtils.isNotBlank(loginDto.getPassword()) && StringUtils.isNotBlank(loginDto.getPhone())){
// 1.1 根据手机号查询用户信息
ApUser dbUser = getOne(Wrappers.<ApUser>lambdaQuery().eq(ApUser::getPhone, loginDto.getPhone()));
if(dbUser == null){
return ResponseResult.errorResult(AppHttpCodeEnum.DATA_EXIST, "用户信息不存在");
}
// 1.2 比对密码
String salt = dbUser.getSalt();
String password = loginDto.getPassword();
if(!dbUser.getPassword().equals(DigestUtils.md5DigestAsHex((password+salt).getBytes()))){
return ResponseResult.errorResult(AppHttpCodeEnum.LOGIN_PASSWORD_ERROR);
}
// 1.3 返回数据 jwt
String token = AppJwtUtil.getToken(dbUser.getId().longValue());
HashMap<String, Object> map = new HashMap<>();
map.put("token", token);
dbUser.setSalt("");
dbUser.setPassword("");
map.put("user", dbUser);
return ResponseResult.okResult(map);
}else{
// 2. 游客登录
HashMap<String, Object> map = new HashMap<>();
map.put("token", AppJwtUtil.getToken(0L));
return ResponseResult.okResult(map);
}
}
图形化工具
<dependency>
<groupId>io.springfoxgroupId>
<artifactId>springfox-swagger2artifactId>
dependency>
<dependency>
<groupId>io.springfoxgroupId>
<artifactId>springfox-swagger-uiartifactId>
dependency>
@Configuration
@EnableSwagger2
public class SwaggerConfiguration {
@Bean
public Docket buildDocket() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(buildApiInfo())
.select()
// 要扫描的API(Controller)基础包
.apis(RequestHandlerSelectors.basePackage("com.heima"))
.paths(PathSelectors.any())
.build();
}
private ApiInfo buildApiInfo() {
Contact contact = new Contact("黑马程序员","","");
return new ApiInfoBuilder()
.title("黑马头条-平台管理API文档")
.description("黑马头条后台api")
.contact(contact)
.version("1.0.0").build();
}
}
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
...
com.heima.common.swagger.SwaggerConfiguration
// controller
...
@Api(value = "app端用户登录", tags = "app端用户登录")
public class ApUserLoginController {
...
...
@ApiOperation("用户登录")
public ResponseResult login(@RequestBody LoginDto loginDto)
{
...
}
}
// model
public class LoginDto {
@ApiModelProperty(value = "手机号", required = true)
private String phone;
@ApiModelProperty(value = "手机号", required = true)
private String password;
}
<dependency>
<groupId>com.github.xiaoymingroupId>
<artifactId>knife4j-spring-boot-starterartifactId>
dependency>
@Configuration
@EnableSwagger2
@EnableKnife4j
@Import(BeanValidatorPluginsConfiguration.class)
public class Swagger2Configuration {
@Bean(value = "defaultApi2")
public Docket defaultApi2() {
Docket docket=new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
//分组名称
.groupName("1.0")
.select()
//这里指定Controller扫描包路径
.apis(RequestHandlerSelectors.basePackage("com.heima"))
.paths(PathSelectors.any())
.build();
return docket;
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("黑马头条API文档")
.description("黑马头条API文档")
.version("1.0")
.build();
}
}
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
...
com.heima.common.swagger.Swagger2Configuration
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-gatewayartifactId>
dependency>
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
dependency>
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-nacos-configartifactId>
dependency>
<dependency>
<groupId>io.jsonwebtokengroupId>
<artifactId>jjwtartifactId>
dependency>
# bootstrap.yml
server:
port: 51601
spring:
application:
name: leadnews-app-gateway
cloud:
nacos:
discovery:
server-addr: 192.168.174.133:8848
config:
server-addr: 192.168.174.133:8848
file-extension: yml
# nacos leadnews-app-gateway.yml
spring:
cloud:
gateway:
globalcors:
add-to-simple-url-handler-mapping: true
corsConfigurations:
'[/**]':
allowedHeaders: "*"
allowedOrigins: "*"
allowedMethods:
- GET
- POST
- DELETE
- PUT
- OPTION
routes:
# 平台管理
- id: user
uri: lb://leadnews-user
predicates:
- Path=/user/**
filters:
- StripPrefix= 1
@Component
public class AuthorizeFilter implements Ordered, GlobalFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 1. 获取request和response对象
ServerHttpRequest request = exchange.getRequest();
ServerHttpResponse response = exchange.getResponse();
// 2. 判断是否登录
if(request.getURI().getPath().contains("/login")){
return chain.filter(exchange);
}
// 3. 获取token
String token = request.getHeaders().getFirst("token");
// 4. 判断token是否存在
if(StringUtils.isBlank(token)){
response.setStatusCode(HttpStatus.UNAUTHORIZED);
return response.setComplete();
}
// 5. 判断token是否有效
try {
Claims claimsBody = AppJwtUtil.getClaimsBody(token);
int result = AppJwtUtil.verifyToken(claimsBody);
if(result==1 || result==2){
response.setStatusCode(HttpStatus.UNAUTHORIZED);
return response.setComplete();
}
} catch (Exception e) {
e.printStackTrace();
response.setStatusCode(HttpStatus.UNAUTHORIZED);
return response.setComplete();
}
// 6. 放行
return chain.filter(exchange);
}
@Override
public int getOrder() {
return 0;
}
}
在nginx安装的conf目录下新建一个文件夹leadnews.conf
,在当前文件夹中新建heima-leadnews-app.conf
文件
heima-leadnews-app.conf配置如下:
upstream heima-app-gateway{
server localhost:51601;
}
server {
listen 8801;
location / {
root D:/workspace/leadnews/app-web/;
index index.html;
}
location ~/app/(.*) {
proxy_pass http://heima-app-gateway/$1;
proxy_set_header HOST $host; # 不改变源请求头的值
proxy_pass_request_body on; #开启获取请求体
proxy_pass_request_headers on; #开启获取请求头
proxy_set_header X-Real-IP $remote_addr; # 记录真实发出请求的客户端IP
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; #记录代理信息
}
}
nginx.conf 把里面注释的内容和静态资源配置相关删除,引入heima-leadnews-app.conf文件加载
#user nobody;
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
# 引入自定义配置文件
include leadnews.conf/*.conf;
}
打开前端项目进行测试 – > http://localhost:8801
黑马程序员. 黑马头条