【黑马头条】-day01环境搭建SpringBoot-Cloud-Nacos



1 环境搭建及简介

在这里插入图片描述

在这里插入图片描述

2 项目介绍

2.1 应用

在这里插入图片描述

2.2 业务说明

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

2.3 技术栈

前端
在这里插入图片描述

后端

在这里插入图片描述

2.4 收获

在这里插入图片描述

2.5 大纲

在这里插入图片描述

3 Nacos准备

3.1 安装Nacos

在这里插入图片描述

1)拉取镜像

docker pull nacos/nacos-server:1.2.0

2)创建容器

docker run --env MODE=standalone --name nacos --restart=always -d -p 8848:8848 nacos/nacos-server:1.2.0

3)查看日志

docker logs -f nacos

在这里插入图片描述

4)访问当前Nacos

http://192.168.204.129:8848/nacos

4 初始工程搭建

4.1 环境准备

4.1.1 导入项目

在这里插入图片描述

解压heima-leadnews.zip,并且导入idea,设置jdk为1.8
在这里插入图片描述

4.1.2 设置本地仓库

respository_new.zip解压到本地仓库文件夹

打开idea-settings设置本地仓库
在这里插入图片描述

修改为
在这里插入图片描述

4.1.3 设置项目编码格式

在这里插入图片描述

4.2 全局异常

在这里插入图片描述

heima-leadnews-common模块下的com.heima.common.exception包下自定义异常类CustomException,如果我们手动抛出异常就需要抛出CustomException类

public class CustomException extends RuntimeException {

    private AppHttpCodeEnum appHttpCodeEnum;

    public CustomException(AppHttpCodeEnum appHttpCodeEnum){
        this.appHttpCodeEnum = appHttpCodeEnum;
    }

    public AppHttpCodeEnum getAppHttpCodeEnum() {
        return appHttpCodeEnum;
    }
}

另外一个类ExceptionCatch类,全局异常拦截类

注解@ControllerAdvice:ControllerAdvice本质上是一个Component,因此也会被当成组件扫描,一视同仁,扫扫扫。

  • 这个类是为那些声明了(@ExceptionHandler、@InitBinder 或 @ModelAttribute注解修饰的)方法的类而提供的专业化的@Component , 以供多个 Controller类所共享。
@ControllerAdvice  //控制器增强类
@Slf4j
public class ExceptionCatch {

    /**
     * 处理不可控异常
     * @param e
     * @return
     */
    @ExceptionHandler(Exception.class)
    @ResponseBody
    public ResponseResult exception(Exception e){
        e.printStackTrace();
        log.error("catch exception:{}",e.getMessage());

        return ResponseResult.errorResult(AppHttpCodeEnum.SERVER_ERROR);
    }

    /**
     * 处理可控异常  自定义异常
     * @param e
     * @return
     */
    @ExceptionHandler(CustomException.class)
    @ResponseBody
    public ResponseResult exception(CustomException e){
        log.error("catch exception:{}",e);
        return ResponseResult.errorResult(e.getAppHttpCodeEnum());
    }
}

在heima-leadnews-model模块下的com.heima.model包下的common包下的enums包下有个枚举类AppHttpCodeEnum,用来存放对异常的说明

public enum AppHttpCodeEnum {

    // 成功段0
    SUCCESS(200,"操作成功"),
    // 登录段1~50
    NEED_LOGIN(1,"需要登录后操作"),
    LOGIN_PASSWORD_ERROR(2,"密码错误"),
    // TOKEN50~100
    TOKEN_INVALID(50,"无效的TOKEN"),
    TOKEN_EXPIRE(51,"TOKEN已过期"),
    TOKEN_REQUIRE(52,"TOKEN是必须的"),
    // SIGN验签 100~120
    SIGN_INVALID(100,"无效的SIGN"),
    SIG_TIMEOUT(101,"SIGN已过期"),
    // 参数错误 500~1000
    PARAM_REQUIRE(500,"缺少参数"),
    PARAM_INVALID(501,"无效参数"),
    PARAM_IMAGE_FORMAT_ERROR(502,"图片格式有误"),
    SERVER_ERROR(503,"服务器内部错误"),
    // 数据错误 1000~2000
    DATA_EXIST(1000,"数据已经存在"),
    AP_USER_DATA_NOT_EXIST(1001,"ApUser数据不存在"),
    DATA_NOT_EXIST(1002,"数据不存在"),
    // 数据错误 3000~3500
    NO_OPERATOR_AUTH(3000,"无权限操作"),
    NEED_ADMIND(3001,"需要管理员权限");

    int code;
    String errorMessage;

    AppHttpCodeEnum(int code, String errorMessage){
        this.code = code;
        this.errorMessage = errorMessage;
    }

    public int getCode() {
        return code;
    }

    public String getErrorMessage() {
        return errorMessage;
    }
}

4.2.1 自动装配

resource下META-INF有spring.factories,只有有微服务引用了heima-leadnews-common,服务器初始化spring容器的时候就会找到spring.factories,把spring.factories中需要自动配置的文件加载到当前微服务的容器中,也就能用全局处理器了。

在这里插入图片描述

4.3 工程主体结构

在这里插入图片描述

5 登录功能开发

5.1 需求分析

在这里插入图片描述

5.1.1 表结构分析

打开本地sql工具,引入sql脚本,创建leadnews_user,有四张表

在这里插入图片描述

在这里插入图片描述

5.1.2 实体类ApUser的导入

在heima-leadnews-model模块下创建com.heima.model.user.pojos包下创建实体类ApUser

@TableName("ap_user"):表的映射

@TableId(value = "id", type = IdType.AUTO):主键的映射

@TableField("name"):其他字段的映射

@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;

}

5.1.3 表结构中salt的解释

salt:密码、通信等加密盐

5.1.3.1 注册过程

在这里插入图片描述

5.1.3.2 登录过程

在这里插入图片描述

6 用户端微服务的搭建

heima-leadnews-service模块是管理其他所有微服务模块

6.1 service模块的依赖说明

在这里插入图片描述

6.2 创建用户微服务模块

在heima-leadnews-service下创建模块

在这里插入图片描述

6.2.1 创建引导类

然后创建一个包com.heima.user,再创建一个引导类UserApplication

@SpringBootApplication: 启动类注解

@EnableDiscoveryClient :集成当前的注册中心,加入注册中心

@MapperScan("com.heima.user.mapper") :继承MybatisPlus,扫描Mapper接口,没有就在com.heima.user下创建mapper包

@SpringBootApplication
@EnableDiscoveryClient
@MapperScan("com.heima.user.mapper")
public class UserApplication {
    public static void main(String[] args) {
        SpringApplication.run(UserApplication.class, args);
    }
}

6.2.2 创建controller.v1、service、mapper、config

controller.v1是不同版本的controller

在这里插入图片描述

6.2.3 创建resources的配置文件

6.2.3.1 bootstrap.yml

若application.yml 和bootstrap.yml在同一目录下:bootstrap.yml 先加载 application.yml后加载,application.yml会覆盖

创建bootstrap.yml

server:
  port: 51801
spring:
  application:
    name: leadnews-user
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.204.129:8848
      config:
        server-addr: 192.168.204.129:8848
        file-extension: yml

这里面暂时只有Nacos的配置,关于数据库的等等都需要在Nacos的配置中心进行配置

在这里插入图片描述

spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/leadnews_user?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC&useSSL=false
    username: root
    password: 123sjbsjb
# 设置Mapper接口所对应的XML文件位置,如果你在Mapper接口中有自定义方法,需要进行该配置
mybatis-plus:
  mapper-locations: classpath*:mapper/*.xml
  # 设置别名包扫描路径,通过该属性可以给包中的类注册别名
  type-aliases-package: com.heima.model.user.pojos


发布查看

6.2.3.2 logback.xml

创建日志文件logback.xml

<?xml version="1.0" encoding="UTF-8"?>

<configuration>
    <!--定义日志文件的存储地址,使用绝对路径-->
    <property name="LOG_HOME" value="D:\Code\JavaCode\HeimaToutiao\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>

6.3 整体用户端框架

在这里插入图片描述

7 登录接口实现

7.1 app登录-接口定义

在这里插入图片描述

7.1.1 DTO的LoginDto类

heima-leadnews-model模块下的com.heima.model.user.pojos.dtos包下创建LoginDto类

@Data
public class LoginDto {
    private String phone;
    private String password;
}

7.1.2 Controller层ApUserLoginController类

再在heima-leadnews-service模块下的com.heima.user.controller.v1下创建ApUserLoginController类

POST请求采用@RequestBody

@RestController
@RequestMapping("/api/v1/login")
public class ApUserLoginController {
    @PostMapping("/login_auth")
    public ResponseResult login(@RequestBody(required=false) LoginDto dto) {
        return null;
    }
}

7.1.3 Mapper层ApUserMapper接口

使用mybatisplus

在com.heima.user.mapper创建ApUserMapper接口

@Mapper
public interface ApUsermapper extends BaseMapper<ApUser> {

}

7.1.4 Service层ApUserService接口

public interface ApUserService extends IService<ApUser>{
}

7.1.5 实现ApUserService接口

@Service
@Transactional
@Slf4j
public class ApUserServiceImpl extends ServiceImpl<ApUsermapper, ApUser> implements ApUserService {
}

@Service标注业务层实现

@Transactional标注事务

7.1.6 完善业务层接口

public interface ApUserService extends IService<ApUser>{
    /**
     * 登录功能
     * @param dto
     * @return
     */
    public ResponseResult login(LoginDto dto);
}

实现方法

@Service
@Transactional
@Slf4j
public class ApUserServiceImpl extends ServiceImpl<ApUsermapper, ApUser> implements ApUserService {
    @Override
    public ResponseResult login(LoginDto dto) {
        return null;
    }
}

7.2 登录思路分析

7.2.1 业务层登录实现

在这里插入图片描述

在ApUserServiceImpl类中实现思路

@Service
@Transactional
@Slf4j
public class ApUserServiceImpl extends ServiceImpl<ApUsermapper, ApUser> implements ApUserService {
    @Override
    public ResponseResult login(LoginDto dto) {
        //1.正常登录 用户名、密码
        if(StringUtils.isNotBlank(dto.getPhone()) && StringUtils.isNotBlank(dto.getPassword())) {
            //1.1 查询用户信息,根据手机号查询用户信息
            ApUser dbUser = getOne(Wrappers.<ApUser>lambdaQuery().eq(ApUser::getPhone, dto.getPhone()));
            if(dbUser == null) {
                return ResponseResult.errorResult(AppHttpCodeEnum.AP_USER_DATA_NOT_EXIST, "用户不存在");
            }
            //1.2 比对密码
            String salt = dbUser.getSalt();
            String password = dto.getPassword();
            String pwd = DigestUtils.md5DigestAsHex((password + salt).getBytes());
            if(!pwd.equals(dbUser.getPassword())) {
                return ResponseResult.errorResult(AppHttpCodeEnum.LOGIN_PASSWORD_ERROR, "密码错误");
            }
            //1.3 没问题的话,返回数据,生成jwt
            String token = AppJwtUtil.getToken(dbUser.getId().longValue());
            Map<String,Object> map=new HashMap<>();
            map.put("token",token);
            //清空敏感信息,前端只要id,手机号,昵称
            ApUser userVO=new ApUser();
            userVO.setId(dbUser.getId());
            userVO.setPhone(dbUser.getPhone());
            userVO.setName(dbUser.getName());
            map.put("user",userVO);
            return ResponseResult.okResult(map);
        }else{
            //2.游客登录
            Map<String,Object> map=new HashMap<>();
            map.put("token",AppJwtUtil.getToken(0L));
            return ResponseResult.okResult(map);
        }
    }
}

加密采用DigestUtils.md5DigestAsHex传入字节流

生成JWT令牌是使用heima-leadnews-utils模块下的com.heima.utils.common包下的AppJWTUtil

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"));

    }

}

7.2.2 Controller注入

@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);
    }
}

7.2.3 测试

启动redis报错

修改bootstrap.yml文件,添加redis地址

redis:
  host: 127.0.0.1
  port: 6379
  database: 0

启动,Nacos的服务管理中有leadnews-user

访问http://localhost:51801/api/v1/login/login_auth

在这里插入图片描述

8 App端网关

在这里插入图片描述
在这里插入图片描述

8.1 导入依赖

在heima-leadnews-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>

8.2 微服务创建网关

8.2.1 AppGateway

针对各个微服务创建相应的网关

在这里插入图片描述

创建引导类com.heima.app.gateway.AppGatewayApplication

@SpringBootApplication
@EnableDiscoveryClient
public class AppGatewayApplication {
    public static void main(String[] args) {
        SpringApplication.run(AppGatewayApplication.class, args);

    }
}

8.2.2 创建配置文件bootstrap.yml

server:
  port: 51601
spring:
  application:
    name: leadnews-app-gateway
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.204.129:8848
      config:
        server-addr: 192.168.204.129:8848
        file-extension: yml

8.2.3 在Nacos中创建配置中心

在这里插入图片描述

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
  • id: user: 这是此路由的唯一标识符。
  • uri: lb://leadnews-user: 当请求匹配到该路由时,它会被路由到"leadnews-user"服务的实例。URI的前缀"lb://"表示路由到负载均衡器。
  • predicates: 定义了路由的匹配规则。在这种情况下,请求路径必须以"/user/"开头才会匹配到此路由。
  • filters: 定义了路由的过滤器。在这里,使用了"StripPrefix"过滤器,该过滤器会将请求的路径中的一层前缀移除。具体来说,这里是将路径中的第一层"/user"移除,以便在转发请求到"leadnews-user"服务时去除不必要的前缀。

访问http://localhost:51601/user/api/v1/login/login_auth

在这里插入图片描述

9 认证过滤器

在这里插入图片描述

9.1 全局过滤器

要实现这个功能,要实现一个全局的过滤器

在heima-leadnews-gateway模块下创建com.heima.app.gateway.filter.AuthorizeFilter类用作全局过滤器

@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是否有效
        //5.1 解析token
        try{
            Claims body = AppJwtUtil.getClaimsBody(token);
            //5.2 判断token是否有效
            int result = AppJwtUtil.verifyToken(body);
            if(result == 1||result == 2) {
                //5.3 token过期
                response.setStatusCode(HttpStatus.UNAUTHORIZED);
                return response.setComplete();
            }
        }catch (Exception e) {
            e.printStackTrace();
            //5.4 token无效
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            return response.setComplete();
        }
        //6.放行
        return chain.filter(exchange);
    }

    /**
     * 过滤器的执行顺序,返回值越小,执行优先级越高
     * @return
     */
    @Override
    public int getOrder() {
        return 0;
    }
}

把AppJwtUtil放入gateway的工具包中

在这里插入图片描述

9.2 测试

包含/login直接放行

在这里插入图片描述

10 app前端项目集成

10.1 Nginx反向代理和静态资源配置

在这里插入图片描述

在这里插入图片描述

访问http://localhost:80

在这里插入图片描述

将静态资源和nginx都放在工作目录下

在nginx的conf目录下创建文件夹leadnews.conf,新建文件heimi-leadnews-app.conf

nginx端口8801然后转发到gateway端口51601,gateway添加user路径后通过Nacos路由到leadnews-user也就是端口51801完成访问

静态资源存放在D:/Code/JavaCode/HeimaToutiao/app-web/展示其目录下的index.html

upstream  heima-app-gateway{
    server localhost:51601;
}

server {
	listen 8801;
	location / {
        root D:/Code/JavaCode/HeimaToutiao/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中引入

#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

在这里插入图片描述

访问成功

  • 26
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Vue黑马头条项目的难点主要包括以下几个方面: 1. 数据流管理:在Vue黑马头条项目中,需要管理大量的数据,包括用户信息、新闻内容、评论等。如何有效地处理并管理这些数据,确保数据的正确性和一致性是一个难点。可以使用Vuex来进行全局的数据管理,并通过状态管理模式来统一管理数据的流动和变化。 2. 组件交互与通信:Vue黑马头条项目中使用了大量的组件,组件之间的交互与通信是其中一个难点。组件之间需要进行数据的传递、事件的派发与监听,如何高效地组织和管理这些组件之间的交互,提高项目的可维护性和扩展性是一个挑战。 3. 页面布局和样式:Vue黑马头条项目的页面比较复杂,需要考虑到不同屏幕尺寸的适配和响应式布局。同时,页面中的样式设计也需要符合美观和用户体验的要求。如何在保持页面布局的灵活性和可扩展性的同时,确保页面样式的一致性和用户友好性也是一个难点。 4. 请求与响应处理:Vue黑马头条项目需要与后台进行数据交互,包括获取新闻内容、发布评论等。在请求与响应处理中,需要考虑到网络请求的错误处理、数据的缓存和异步操作的管理等问题,确保用户在使用过程中的流畅性和体验。 5. 性能优化:Vue黑马头条项目中的数据量较大,页面频繁地进行数据的渲染和更新,对页面的性能和响应速度提出了要求。如何通过合理的数据缓存、懒加载、组件按需加载等方式进行性能优化,提高项目的执行效率和用户体验,是一个需要解决的难题。 通过了解和解决这些难点,可以更好地设计和实现Vue黑马头条项目,提高项目的开发效率和用户体验。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AAA码农宝哥.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值