JavaWeb_LeadNews_Day1-接口测试, app端登录, 网关, 前端集成

搭建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
    
    • MODE=standalone: 单机版
    • --restart=always: 开机启动
    • -p 8848:8848: 映射端口
    • -d: 创建一个守护式容器在后台运行

搭建初始工程

heima-leadnews: 父工程, 统一管理项目依赖, 继承SpringBoot

  • heima-leadnews-common: 通用配置
  • heima-leadnews-feign-api: feign对外的接口
  • heima-leadnews-model: pojo, dto
  • heima-leadnews-utils: 通用工具
  • heima-leadnews-gateway: 管理网关工程
  • heima-leadnews-service: 管理微服务
  • heima-leadnews-test: 测试案例

app登录

表结构

新建数据库leadnews_user

表名称说明
ap_userAPP用户信息表
ap_user_fanAPP用户粉丝信息表
ap_user_followAPP用户关注信息表
ap_user_realnameAPP实名认证信息表

密码加盐

  • md5是不可逆加密, md5相同的密码每次加密都一样, 不安全
  • 在md5的基础上手动加盐处理
  • 根据用户生成salt(随机字符串), md5加密密码+salt

搭建用户微服务

  1. heima-leadnews-service下创建模块heima-leadnews-user
  2. 启动类
    @Slf4j
    @SpringBootApplication
    @EnableDiscoveryClient
    @MapperScan("com.heima.user.mapper")
    public class UserApplication {
        public static void main(String[] args) {
            SpringApplication.run(UserApplication.class, args);
            log.info("项目启动成功");
        }
    }
    
  3. bootstrap.yml
    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
    
  4. 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>
    

功能实现

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

接口测试工具

postman

图形化工具

swagger

  • 依赖
    <!-- swagger -->
    <dependency>
        <groupId>io.springfox</groupId>
        <artifactId>springfox-swagger2</artifactId>
    </dependency>
    <dependency>
        <groupId>io.springfox</groupId>
        <artifactId>springfox-swagger-ui</artifactId>
    </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;
    }
    
  • 访问地址
    http://localhost:51801/swagger-ui.html

knife4j

  • 依赖
    <dependency>
        <groupId>com.github.xiaoymin</groupId>
        <artifactId>knife4j-spring-boot-starter</artifactId>
    </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
    
  • 访问地址
    http://localhost:51801/doc.html

app端网关

搭建网关

  • 依赖
    <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>
    
  • 配置
    # 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前端集成

在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

来源

黑马程序员. 黑马头条

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
实现省市区三级联动的关键是建立好数据库,并且编写好对应的 SQL 语句。以下是一个简单的数据库设计: - 省份表 province,包括字段 id 和 name。 - 城市表 city,包括字段 id、name 和省份的外键 province_id。 - 区县表 district,包括字段 id、name 和城市的外键 city_id。 接下来是建表语句: ```sql -- 省份表 CREATE TABLE `province` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(20) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- 城市表 CREATE TABLE `city` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(20) NOT NULL, `province_id` int(11) NOT NULL, PRIMARY KEY (`id`), KEY `province_id` (`province_id`), CONSTRAINT `city_ibfk_1` FOREIGN KEY (`province_id`) REFERENCES `province` (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- 区县表 CREATE TABLE `district` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(20) NOT NULL, `city_id` int(11) NOT NULL, PRIMARY KEY (`id`), KEY `city_id` (`city_id`), CONSTRAINT `district_ibfk_1` FOREIGN KEY (`city_id`) REFERENCES `city` (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; ``` 接下来是查询省份、城市、区县的 SQL 语句: ```sql -- 查询所有省份 SELECT id, name FROM province; -- 查询某个省份下的所有城市 SELECT id, name FROM city WHERE province_id = ?; -- 查询某个城市下的所有区县 SELECT id, name FROM district WHERE city_id = ?; ``` 在 Java Web 项目中,可以使用 Ajax 和 JSON 技术实现省市区三级联动。前端页面发送 Ajax 请求,后端通过 JDBC 连接数据库,查询对应的省份、城市、区县信息,并以 JSON 格式返回给前端页面。前端页面再解析 JSON 数据,更新页面的省份、城市、区县下拉框选项。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Y_cen

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

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

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

打赏作者

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

抵扣说明:

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

余额充值