• 使用springboot每日推送早安问候语到用户微信【部署篇】


    上一篇介绍文章

    上一篇介绍文章

    https://blog.csdn.net/weixin_45206218/article/details/127872136
    
    • 1

    代码仓库

    代码仓库

    https://gitee.com/stevezhaozps/daily-weather
    
    • 1

    前期准备

    • 一台云服务器
    • 云服务器安装MySQL8.x
    • 云服务器安装jdk8

    数据库初始化

    由于本项目使用的是springdatajpa,所以不需要我们手动建表,只需要建数据库启动项目,会自动建表

    CREATE DATABASE daily_weather;
    
    • 1

    这里提供数据库备份

    /*
     Navicat Premium Data Transfer
    
     Source Server         : win11
     Source Server Type    : MySQL
     Source Server Version : 50740 (5.7.40-log)
     Source Host           : localhost:3306
     Source Schema         : daily_weather
    
     Target Server Type    : MySQL
     Target Server Version : 50740 (5.7.40-log)
     File Encoding         : 65001
    
     Date: 17/11/2022 15:03:50
    */
    
    SET NAMES utf8mb4;
    SET FOREIGN_KEY_CHECKS = 0;
    
    -- ----------------------------
    -- Table structure for user_info
    -- ----------------------------
    DROP TABLE IF EXISTS `user_info`;
    CREATE TABLE `user_info`  (
      `id` bigint(20) NOT NULL,
      `bir_time` datetime NULL DEFAULT NULL,
      `city` varchar(255) CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL,
      `create_time` datetime NULL DEFAULT NULL,
      `district_id` varchar(255) CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL,
      `nickname` varchar(255) CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL,
      `scq_time` datetime NULL DEFAULT NULL,
      `type` int(11) NULL DEFAULT NULL,
      `update_time` datetime NULL DEFAULT NULL,
      `wechat_id` varchar(255) CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL,
      PRIMARY KEY (`id`) USING BTREE
    ) ENGINE = MyISAM CHARACTER SET = latin1 COLLATE = latin1_swedish_ci ROW_FORMAT = Dynamic;
    
    SET FOREIGN_KEY_CHECKS = 1;
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    项目配置

    如何申请见上一篇文章

    server:
      port: 43310
    # 微信配置
    tencent:
      wechat:
        appId: 微信申请appid
        appSecret: 微信申请appSecret
      # 模板消息集合
      templatelist:
        - type: 1
          templateId: 模板id
        - type: 2
          templateId: 模板id
        - type: 3
          templateId: 模板id
    # 百度天气配置
    baidu:
      server: https://api.map.baidu.com
      ak: 百度申请的ak
    # 天行数据
    tianxin:
      server: http://api.tianapi.com
      key: 天行数据的key
    spring:
      mvc:
        pathmatch:
          matching-strategy: ant_path_matcher
      datasource:
        type: com.zaxxer.hikari.HikariDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://127.0.0.1:3306/daily_weather?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
        username: 数据库用户
        password: 数据库密码
        hikari:
          minimum-idle: 5
          # 空闲连接存活最大时间,默认600000(10分钟)
          idle-timeout: 180000
          # 连接池最大连接数,默认是10
          maximum-pool-size: 10
          # 此属性控制从池返回的连接的默认自动提交行为,默认值:true
          auto-commit: true
          # 连接池名称
          pool-name: MyHikariCP
          # 此属性控制池中连接的最长生命周期,值0表示无限生命周期,默认1800000即30分钟
          max-lifetime: 1800000
          # 数据库连接超时时间,默认30秒,即30000
          connection-timeout: 30000
          connection-test-query: SELECT 1
      jpa:
        show-sql: true # 默认false,在日志里显示执行的sql语句
        database: mysql
        database-platform: org.hibernate.dialect.MySQL5Dialect
        hibernate:
          ddl-auto: update #指定为update,每次启动项目检测表结构有变化的时候会新增字段,表不存在时会 新建,如果指定create,则每次启动项目都会清空数据并删除表,再新建
          naming:
            #指定jpa的自动表生成策略,驼峰自动映射为下划线格式7
            implicit-strategy: org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyJpaImpl
            #physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
    # 日志
    #logging:
    #  config: classpath:logback-spring-dev.xml
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61

    项目结构介绍

    在这里插入图片描述

    • advice : 负责统一封装处理前端返回数据格式
    • common : 统一结果封装
    • config: 项目配置
    • domain: 实体类
    • enums: 服务状态枚举类
    • exception: 异常处理和自定义异常
    • job: 定时任务
    • remote: 第三方接口调用,使用openfeign
    • repository: 数据库操作层,dao/mapper层
    • rest: 视图控制层
    • service: 业务处理层

    统一结果封装
    注意返回String类型需要特殊处理

    package com.zhao.wechat.advice;
    
    
    import com.fasterxml.jackson.core.JsonProcessingException;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import com.zhao.wechat.common.Result;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.core.MethodParameter;
    import org.springframework.http.MediaType;
    import org.springframework.http.converter.HttpMessageConverter;
    import org.springframework.http.server.ServerHttpRequest;
    import org.springframework.http.server.ServerHttpResponse;
    import org.springframework.web.bind.annotation.RestControllerAdvice;
    import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
    
    /**
     * 对前端响应结果统一封装
     */
    @Slf4j
    @RestControllerAdvice(basePackages = {"com.zhao.wechat.rest"})
    public class ApiResponseAdvice implements ResponseBodyAdvice<Object> {
    
    
    	/**
    	 * 打印统一请求响应规范
    	 */
    	ApiResponseAdvice(){
    		log.info("启动请求统一响应规范... ...");
    	}
    
    
    	/**
    	 * 判断是否需要对返回值进行封装
    	 * @param returnType the return type
    	 * @param converterType the selected converter type
    	 * @return
    	 */
    	@Override
    	public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
    		// 如果返回的结果是Result.class类型就不用封装
    		if (returnType.getParameterType().equals(Result.class)){
    			return false;
    		}
    		return true;
    	}
    
    	/**
    	 * 对返回前端的值统一封装
    	 * @param body the body to be written
    	 * @param returnType the return type of the controller method
    	 * @param selectedContentType the content type selected through content negotiation
    	 * @param selectedConverterType the converter type selected to write to the response
    	 * @param request the current request
    	 * @param response the current response
    	 * @return
    	 */
    	@Override
    	public Object beforeBodyWrite(Object body,
    								  MethodParameter returnType,
    								  MediaType selectedContentType,
    								  Class<? extends HttpMessageConverter<?>> selectedConverterType,
    								  ServerHttpRequest request,
    								  ServerHttpResponse response) {
    	 if (returnType.getParameterType().equals(String.class)){
    		 // 如果是String类需要特殊处理
    		 ObjectMapper objectMapper = new ObjectMapper();
    		 try {
    			 // 设置响应数据格式为json
    			 response.getHeaders().add("content-type","application/json;charset=UTF-8");
    			 return objectMapper.writeValueAsString(Result.success(body));
    		 } catch (JsonProcessingException e) {
    			 throw new RuntimeException(e);
    		 }
    	 }
    	 return Result.success(body);
    	}
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79

    项目打包

    • 找到maven
    • 先点clean清理,再点package打包
      在这里插入图片描述
      在target找到jar包,准备上传到云服务器
      在这里插入图片描述

    项目部署

    xftp 上传文件 + xshell

    通过xftp上传到云服务器

    在这里插入图片描述

    xshell执行jar

    切换到当前jar目录下

    # 启动
    java -jar daily-weather-1.0.0.jar >/dev/null 2&1 &
    # 启动成功会出现log目录,cd到log目录下可查看项目运行日志,有无报错
    
    # 查看项目是否在运行
    ps -ef | grep daily-weather-1.0.0.jar
    # 可看到线程的pid
    kill -9 pid号,可以杀死当前运行的项目
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    通过swagger访问

    正常启动成功后,使用公网ip:端口/doc.html可以访问swagger页面
    
    • 1
  • 相关阅读:
    前端必备的 HTTP 知识!看这篇就够了!!
    C++ 把类封装成静态链接库
    非范型ArrayList和泛型List<T>
    Flask 项目结构
    python 构建数组的方法
    帧同步相关总结
    龙芯杯编译文件学习记录
    C 学生管理系统 打印/修改指定位置信息
    【Java SE】static成员及代码块
    go基础10 -字符串的高效构造与转换
  • 原文地址:https://blog.csdn.net/weixin_45206218/article/details/127904078