赞
踩
可以直接参照各种虚拟机安装centos7,不必拘泥于课程所给的镜像,只要保证能与外界ping通即可。后续环境可以自行安装。
同时使用mac的m系列芯片的同学可以直接不使用虚拟机直接在本地下载docker配置环境(注意要适配ARM架构)。
配置Maven
通过逆向工程生成
package com.heima.model.user.pojos; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; import java.io.Serializable; import java.util.Date; /** * <p> * APP用户信息表 * </p> * * @author itheima */ @Data @TableName("ap_user") public class ApUser implements Serializable { private static final long serialVersionUID = 1L; /** * 主键 */ @TableId(value = "id", type = IdType.AUTO) private Integer id; /** * 密码、通信等加密盐 */ @TableField("salt") private String salt; /** * 用户名 */ @TableField("name") private String name; /** * 密码,md5加密 */ @TableField("password") private String password; /** * 手机号 */ @TableField("phone") private String phone; /** * 头像 */ @TableField("image") private String image; /** * 0 男 1 女 2 未知 */ @TableField("sex") private Boolean sex; /** * 0 未 1 是 */ @TableField("is_certification") private Boolean certification; /** * 是否身份认证 */ @TableField("is_identity_authentication") private Boolean identityAuthentication; /** * 0正常 1锁定 */ @TableField("status") private Boolean status; /** * 0 普通用户 1 自媒体人 2 大V */ @TableField("flag") private Short flag; /** * 注册时间 */ @TableField("created_time") private Date createdTime; }
在下面新建一个工程
bootstrap配置
server:
port: 51801
spring:
application:
name: leadnews-user
cloud:
nacos:
discovery:
server-addr: 192.168.200.130:8848
config:
server-addr: 192.168.200.130:8848
file-extension: yml
使用nacos创建新集群
spring:
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/leadnews_user?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
username: root
password: root
# 设置Mapper接口所对应的XML文件位置,如果你在Mapper接口中有自定义方法,需要进行该配置
mybatis-plus:
mapper-locations: classpath*:mapper/*.xml
# 设置别名包扫描路径,通过该属性可以给包中的类注册别名
type-aliases-package: com.heima.model.user.pojos
配置logback.xml
<?xml version="1.0" encoding="UTF-8"?> <configuration> <!--定义日志文件的存储地址,使用绝对路径--> <property name="LOG_HOME" value="e:/logs"/> <!-- Console 输出设置 --> <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符--> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern> <charset>utf8</charset> </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}.log</fileNamePattern> </rollingPolicy> <encoder> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern> </encoder> </appender> <!-- 异步输出 --> <appender name="ASYNC" class="ch.qos.logback.classic.AsyncAppender"> <!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 --> <discardingThreshold>0</discardingThreshold> <!-- 更改默认的队列的深度,该值会影响性能.默认值为256 --> <queueSize>512</queueSize> <!-- 添加附加的appender,最多只能添加一个 --> <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="ASYNC"/>--> <appender-ref ref="FILE"/> <appender-ref ref="CONSOLE"/> </root> </configuration>
下面分Controller,Service,ServiceImpl层,与Mapper层依次输入代码
@RestController
@RequestMapping("/api/v1/login")
public class ApUserLoginController {
@Autowired
private APUserService apUserService;
@PostMapping("/login_auth")
public ResponseResult login(@RequestBody LoginDto dto){
return apUserService.login(dto);
}
}
package com.heima.user.service; import com.baomidou.mybatisplus.extension.service.IService; import com.heima.model.common.dtos.ResponseResult; import com.heima.model.common.user.dtos.LoginDto; import com.heima.model.common.user.pojos.ApUser; public interface APUserService extends IService<ApUser> { /** * app端登录功能 * @param dto * @return */ public ResponseResult login(LoginDto dto); }
@Service @Transactional @Slf4j /** * ApUserMapper:这是一个 MyBatis-Plus 的 Mapper 接口,通常用于定义数据库操作的方法。 * ApUser:这是一个实体类,表示数据库中的一张表。 */ public class ApUserServiceImpl extends ServiceImpl<ApUserMapper, ApUser> implements APUserService { /** * app登录功能 * @param dto * @return */ @Override public ResponseResult login(LoginDto dto) { //1.正常登录用户用户名和密码 if (StringUtils.isNotEmpty(dto.getPhone())&&StringUtils.isNotEmpty(dto.getPassword())){ //1.1根据手机号从数据库中查询用户信息 ApUser dbUser = getOne(Wrappers.<ApUser>lambdaQuery().eq(ApUser::getPhone, dto.getPhone())); if (dbUser == null){ return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST,"用户信息不存在"); } //1.2比对密码 String salt = dbUser.getSalt(); String password = dto.getPassword(); String pswd = DigestUtils.md5DigestAsHex((password + salt).getBytes()); if (!pswd.equals(dbUser.getPassword())){ return ResponseResult.errorResult(AppHttpCodeEnum.LOGIN_PASSWORD_ERROR); } //1.3 返回数据jwt user String token = AppJwtUtil.getToken(dbUser.getId().longValue()); //跟接口返回值描述保持一致 Map<String, Object> map = new HashMap<>(); map.put("token",token); dbUser.setSalt(""); dbUser.setPassword(""); map.put("user",dbUser); return ResponseResult.okResult(map); }else { //2.游客登录 Map<String,Object> map = new HashMap<>(); map.put("token",AppJwtUtil.getToken(0L)); return ResponseResult.okResult(map); } } }
@Mapper
public interface ApUserMapper extends BaseMapper<ApUser> {
}
使用接口工具类进行测试
引入依赖,在heima-leadnews-model和heima-leadnews-common模块中引入该依赖
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
</dependency>
只需要在heima-leadnews-common中进行配置即可,因为其他微服务工程都直接或间接依赖即可。
新增:com.heima.common.swagger.SwaggerConfiguration
package com.heima.common.swagger; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import springfox.documentation.builders.ApiInfoBuilder; import springfox.documentation.builders.PathSelectors; import springfox.documentation.builders.RequestHandlerSelectors; import springfox.documentation.service.ApiInfo; import springfox.documentation.service.Contact; import springfox.documentation.spi.DocumentationType; import springfox.documentation.spring.web.plugins.Docket; import springfox.documentation.swagger2.annotations.EnableSwagger2; @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(); } }
在heima-leadnews-common模块中的resources目录中新增以下目录和文件
文件:resources/META-INF/Spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.heima.common.swagger.SwaggerConfiguration
给Controller和DTO更新注解
@RestController
@RequestMapping("/api/v1/login")
@Api(value = "app端用户登录",tags = "app端用户登录")
public class ApUserLoginController {
@Autowired
private ApUserService apUserService;
@PostMapping("/login_auth")
@ApiOperation("用户登录")
public ResponseResult login(@RequestBody LoginDto dto){
return apUserService.login(dto);
}
}
@Data
public class LoginDto {
/**
* 手机号
*/
@ApiModelProperty(value = "手机号",required = true)
private String phone;
/**
* 密码
*/
@ApiModelProperty(value = "密码",required = true)
private String password;
}
打开Swagger
(1)在heima-leadnews-gateway导入以下依赖
pom文件
<dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> </dependency> </dependencies>
(2)在heima-leadnews-gateway下创建heima-leadnews-app-gateway微服务
引导类:
package com.heima.app.gateway;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient //开启注册中心
public class AppGatewayApplication {
public static void main(String[] args) {
SpringApplication.run(AppGatewayApplication.class,args);
}
}
bootstrap.yml
server:
port: 51601
spring:
application:
name: leadnews-app-gateway
cloud:
nacos:
discovery:
server-addr: 192.168.200.130:8848
config:
server-addr: 192.168.200.130:8848
file-extension: yml
在nacos的配置中心创建dataid为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
bootstrap
server:
port: 51601
spring:
application:
name: leadnews-app-gateway
cloud:
nacos:
discovery:
server-addr: localhost:8848
config:
server-addr: localhost:8848
file-extension: yml
设置权限过滤器
package com.heima.app.gateway.filter; import com.heima.app.gateway.util.AppJwtUtil; import io.jsonwebtoken.Claims; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang.StringUtils; import org.springframework.cloud.gateway.filter.GatewayFilterChain; import org.springframework.cloud.gateway.filter.GlobalFilter; import org.springframework.core.Ordered; import org.springframework.http.HttpStatus; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.http.server.reactive.ServerHttpResponse; import org.springframework.stereotype.Component; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Mono; @Component @Slf4j 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); } /** * 优先级设置: 值越小 优先级越高 * @return */ @Override public int getOrder() { return 0; } }
package com.heima.app.gateway.util; import io.jsonwebtoken.*; import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; import java.util.*; public class AppJwtUtil { // TOKEN的有效期一天(S) private static final int TOKEN_TIME_OUT = 3_600; // 加密KEY private static final String TOKEN_ENCRY_KEY = "MDk4ZjZiY2Q0NjIxZDM3M2NhZGU0ZTgzMjYyN2I0ZjY"; // 最小刷新间隔(S) private static final int REFRESH_TIME = 300; // 生产ID public static String getToken(Long id){ Map<String, Object> claimMaps = new HashMap<>(); claimMaps.put("id",id); long currentTime = System.currentTimeMillis(); return Jwts.builder() .setId(UUID.randomUUID().toString()) .setIssuedAt(new Date(currentTime)) //签发时间 .setSubject("system") //说明 .setIssuer("heima") //签发者信息 .setAudience("app") //接收用户 .compressWith(CompressionCodecs.GZIP) //数据压缩方式 .signWith(SignatureAlgorithm.HS512, generalKey()) //加密方式 .setExpiration(new Date(currentTime + TOKEN_TIME_OUT * 1000)) //过期时间戳 .addClaims(claimMaps) //cla信息 .compact(); } /** * 获取token中的claims信息 * * @param token * @return */ private static Jws<Claims> getJws(String token) { return Jwts.parser() .setSigningKey(generalKey()) .parseClaimsJws(token); } /** * 获取payload body信息 * * @param token * @return */ public static Claims getClaimsBody(String token) { try { return getJws(token).getBody(); }catch (ExpiredJwtException e){ return null; } } /** * 获取hearder body信息 * * @param token * @return */ public static JwsHeader getHeaderBody(String token) { return getJws(token).getHeader(); } /** * 是否过期 * * @param claims * @return -1:有效,0:有效,1:过期,2:过期 */ public static int verifyToken(Claims claims) { if(claims==null){ return 1; } try { // claims.getExpiration() // .before(new Date()); // 需要自动刷新TOKEN if((claims.getExpiration().getTime()-System.currentTimeMillis())>REFRESH_TIME*1000){ return -1; }else { return 0; } } catch (ExpiredJwtException ex) { return 1; }catch (Exception e){ return 2; } } /** * 由字符串生成加密key * * @return */ public static SecretKey generalKey() { byte[] encodedKey = Base64.getEncoder().encode(TOKEN_ENCRY_KEY.getBytes()); SecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES"); return key; } public static void main(String[] args) { /* Map map = new HashMap(); map.put("id","11");*/ System.out.println(AppJwtUtil.getToken(1102L)); Jws<Claims> jws = AppJwtUtil.getJws("eyJhbGciOiJIUzUxMiIsInppcCI6IkdaSVAifQ.H4sIAAAAAAAAADWLQQqEMAwA_5KzhURNt_qb1KZYQSi0wi6Lf9942NsMw3zh6AVW2DYmDGl2WabkZgreCaM6VXzhFBfJMcMARTqsxIG9Z888QLui3e3Tup5Pb81013KKmVzJTGo11nf9n8v4nMUaEY73DzTabjmDAAAA.4SuqQ42IGqCgBai6qd4RaVpVxTlZIWC826QA9kLvt9d-yVUw82gU47HDaSfOzgAcloZedYNNpUcd18Ne8vvjQA"); Claims claims = jws.getBody(); System.out.println(claims.get("id")); } }
①:解压资料文件夹中的压缩包nginx-1.18.0.zip
②:解压资料文件夹中的前端项目app-web.zip
③:配置nginx.conf文件
在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/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;
}
④ :启动nginx
在nginx安装包中使用命令提示符打开,输入命令nginx启动项目
可查看进程,检查nginx是否启动
重新加载配置文件:nginx -s reload
⑤:打开前端项目进行测试 – > http://localhost:8801
用谷歌浏览器打开,调试移动端模式进行访问
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。