【项目】黑马头条
目录结构
全局异常
登录手动加密(md5 + 随机字符串)
【问题】md5是不可逆加密,md5相同的密码每次加密都一样,不安全。
【解决】在md5的基础上手动加盐(salt)处理
校验过程:
接口测试
1. ApiFox中测试
2. swagger
- 引入依赖
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
</dependency>
- 在common模块下添加swagger配置类:
@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();
}
}
由于其他model下的包名和common的包名不一样,为了让其他微服务可以扫描到这个配置类,需要在resources目录中添加该配置类的全类名:
- swagger的常用注解
- @Api:修饰整个类,描述Controller的作用
- @ApiOperation:描述接口
- @ApiModelProperty:描述属性
成功后启动项目,浏览器访问:
http://localhost:51801/swagger-ui.html
3. knife4j(常用)
knife4j继承了swagger,功能比swagger更强大,也会生成接口文档
- 引入依赖
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
</dependency>
- 在common中添加配置类:
@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();
}
}
同样也需要在resources目录中添加该配置类的全类名
成功后启动项目,浏览器访问:http://host:port/doc.html
网关
1. 配置网关
一个父模块(heima-leadnews-gateway)下,放多个子模块(heima-leadnews-app-gateway)。
- 在父模块中引入依赖
<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>
- 编写子模块的引导类
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: heima-leadnews-gateway
cloud:
nacos:
discovery:
server-addr: 192.168.140.102:8848
config:
server-addr: 192.168.140.102:8848
file-extension: 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
2. 设置认证过滤器
@Component
public class AuthorizeFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 1. 获取request、response对象
ServerHttpResponse response = exchange.getResponse();
ServerHttpRequest request = exchange.getRequest();
// 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); // 返回401未授权
return response.setComplete();
}
// 5. 判断token是否有效
try {
if(!AppJwtUtil.isValidToken(token)) {
// token过期
response.setStatusCode(HttpStatus.UNAUTHORIZED);
return response.setComplete();
}
return chain.filter(exchange); // 放行
}catch (Exception e) {
response.setStatusCode(HttpStatus.UNAUTHORIZED);
return response.setComplete(); // 抛异常,结束
}
}
/**
* 优先级设置,值越小,优先级越高
* @return
*/
@Override
public int getOrder() {
return 0;
}
}
认证过滤器用来拦截前端发过来的请求,写在网关里。
文章列表
表的拆分——垂直分表
将一个表的字段分散到多个表,每个表存储其中一部分字段
优势
- 减少IO争抢,减少锁表的几率(查看文章信息与文章内容互不影响)
- 充分发挥高频数据的操作效率,对文章信息操作的高频率不会被操作文章详情数据的低效率拖累。
拆分规则
- 把不常用的字段单独放在一张表
- 把text、blob等大字段拆分出来单独放在一张表
- 经常组合查询的字段单独放在一张表
文章详情
方案1. 直接查文章内容表
用户某一条文章,根据id去查询文章内容表,返回渲染页面
方案2. 静态模板展示(效率高)
把文章的内容变成静态的html文件,把生成之后的文件上传到minio中,并保存生成的html存入文章信息表中(static_url字段),前端渲染的时候,直接获取文章信息表的static_url字段,然后去minIO里获取静态访问页面即可。
Freemaker知识点:Freemarker模板引擎技术
持续更新中…
原文地址:https://blog.csdn.net/qq_57882997/article/details/145242891
免责声明:本站文章内容转载自网络资源,如侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!