新手在Spring boot + VUE2 项目的常见问题及接口测试工具

110 阅读3分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

新手在Spring boot + VUE2 项目的常见问题及接口测试工具

Spring boot

搭建配置

application.yml文件模板

注:在mysql配置中,mysql8.0以下开启useSSL可能会导致报错,8.0以上不开启可能会报错

# 配置端口
server:
  port: 8080
spring:
  # 配置数据源
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/sport1?serverTimezone=UTC&characterEncoding=utf8&useUnicode=true&useSSL=true
    username: root
#    mysql8以下的密码不需要单引号
#    password: sport
    password: 'zgx949'
    type: com.alibaba.druid.pool.DruidDataSource
# mybatis-plus相关配置
mybatis-plus:
  # xml扫描,多个目录用逗号或者分号分隔(告诉 Mapper 所对应的 XML 文件位置)
  mapper-locations: classpath:mapper/*.xml
  # 以下配置均有默认值,可以不设置
  global-config:
    db-config:
      #主键类型 AUTO:"数据库ID自增" INPUT:"用户输入ID",ID_WORKER:"全局唯一ID (数字类型唯一ID)", UUID:"全局唯一ID UUID";
      id-type: auto
      #字段策略 IGNORED:"忽略判断"  NOT_NULL:"非 NULL 判断")  NOT_EMPTY:"非空判断"
      field-strategy: NOT_EMPTY
      #数据库类型
      db-type: MYSQL
  configuration:
    # 是否开启自动驼峰命名规则映射:从数据库列名到Java属性驼峰命名的类似映射
    map-underscore-to-camel-case: true
    # 如果查询结果中包含空值的列,则 MyBatis 在映射的时候,不会映射这个字段
    call-setters-on-nulls: true
    # 这个配置会将执行的sql打印出来,在开发或测试的时候可以用
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

pom.xml模板

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.6.2</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>sport</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>sport</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>11</java.version>
    </properties>
​
    <dependencies>
​
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!-- mybatisPlus 核心库 -->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.1.0</version>
        </dependency>
        <!-- 引入阿里数据库连接池 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.6</version>
        </dependency>
        <!-- JWT验证依赖-->
        <dependency>
            <groupId>com.auth0</groupId>
            <artifactId>java-jwt</artifactId>
            <version>3.5.0</version>
        </dependency>
​
​
    </dependencies>
​
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>org.mybatis.generator</groupId>
                <artifactId>mybatis-generator-maven-plugin</artifactId>
                <version>1.3.2</version>
                <configuration>
                    <!-- 自动生成代码的配置文件地址 -->
                    <configurationFile>${basedir}/src/main/resources/generator/generatorConfig.xml</configurationFile>
                    <verbose>true</verbose>
                    <overwrite>true</overwrite>
                </configuration>
            </plugin>
​
        </plugins>
    </build></project>

常见问题

包的目录结构

各层介绍
作用
Bean实体对象(和数据库表、字段对应)
Controller控制对应url的动作
Service对应功能接口模块(需要有一个接口和一个具体实现类)
Mapper查询数据库并映射到Bean中
Utils工具类(杂七杂八都放里头)
Config插件或者拦截器的配置(如:Mybatis、JWT等配置)
Annotation配置@注解方法(可以用于定义Token验证之类的接口)
各层模板代码
  • Bean
package com.example.sport.Bean;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
​
@TableName("admin")
public class AdminBean {
    @TableId
    private int id;
    @TableField("username")
    private String username;
    @TableField("password")
    private String password;
    @TableField("name")
    private String name;
    @TableField("level")
    private int level;
    @TableField("college_id")
    private int collegeId;
    @TableField("is_delete")
    private int isDelete;
}
  • Controller
package com.example.sport.Controller;
import com.example.sport.Bean.AdminBean;
import com.example.sport.Bean.menuOptionsBean;
import com.example.sport.Service.AdminService;
import com.example.sport.Utils.CommonApi;
import com.example.sport.Utils.ParamsFormater;
import com.example.sport.Annotation.TokenRequired;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.*;
​
@RestController
@CrossOrigin
@RequestMapping("/admin")
public class Admin {
​
    @Autowired
    private AdminService adminService;
​
    /**
     * @Description: 获取所有管理员信息
     * @Param:
     * @return:
     * @Author: 左手
     * @Date: 2022-01-18
     */
    @GetMapping("list")
    @TokenRequired
    public Map<String, Object> getAdmins(@RequestParam Map<String, Object> params) {
        // 解析页面分页参数
        Map<String, Object> data = ParamsFormater.pageParams(params);
​
        // 分页查询
        List<AdminBean> admins = adminService.getAdmin((int)data.get("page"), (int)data.get("pageSize"));
        return CommonApi.success(admins, adminService.countAdmin());
    }
}
​
  • Service

    接口:

 package com.example.sport.Service;
 import com.example.sport.Bean.AdminBean;
 import com.example.sport.Bean.MenusBean;
 import com.example.sport.Bean.menuOptionsBean;
 import java.util.List;
 import java.util.Map;
 
 public interface AdminService {
 
     /**
      * @Description: 获取管理员用户列表(分页)接口
      * @Param: int page 页数
      * @Param: int pageSize 页面大小
      * @return: AdminBean
      * @Author: 左手
      * @Date: 2022-01-18
      */
     List<AdminBean> getAdmin(int page, int pageSize);
 }

实现Impl:

package com.example.sport.Service.Impl;
​
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.sport.Bean.AdminBean;
import com.example.sport.Bean.MenusBean;
import com.example.sport.Bean.menuOptionsBean;
import com.example.sport.Controller.Admin;
import com.example.sport.Mapper.AdminMapper;
import com.example.sport.Mapper.MenusMapper;
import com.example.sport.Service.AdminService;
import com.example.sport.Utils.JwtUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
​
/**
 * @program: sport
 * @description: 管理员服务层实现
 * @author: 左手
 * @create: 2022-01-18 10:40
 **/@Service
public class AdminServiceImpl implements AdminService {
​
    @Autowired
    private AdminMapper adminMapper;
​
    @Override
    public List<AdminBean> getAdmin(int page, int pageSize) {
        List<AdminBean> result = adminMapper.selectPage(new Page<>(page, pageSize), null).getRecords();
        return result;
    }
}
​
  • Mapper
package com.example.sport.Mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.sport.Bean.AdminBean;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.ResultType;
import org.apache.ibatis.annotations.Select;
import org.springframework.stereotype.Repository;
import java.util.ArrayList;
import java.util.List;
​
@Repository
@Mapper
public interface AdminMapper extends BaseMapper<AdminBean> {
​
    /**
    * @Description: 自定义sql查询(非必要)
    * @Param:
    * @return:
    * @Author: 左手
    * @Date: 2022-02-14
    */
    @Select({"${sql}"})
    @ResultType(ArrayList.class)
    List<AdminBean> executeQuery(@Param("sql") String sql);
​
}
​
​
  • Utils

(无需指定模板)

package com.example.sport.Utils;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTVerificationException;
import java.util.Date;
import java.util.HashMap;
​
/**
 * @program: sport
 * @description: JWT签名计算计算工具
 * @author: 左手
 * @create: 2022-02-13 13:50
 **/
public class JwtUtil {
​
    //过期时间86400分钟
    private static final long EXPIRE_TIME = 24*60*60*1000;
​
    //生成签名,86400分钟后过期
    public static String sign(String username,String id,String password){
        //过期时间
        Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME);
        //使用用户密码作为私钥进行加密
        Algorithm algorithm = Algorithm.HMAC256(password);
        //设置头信息
        HashMap<String, Object> header = new HashMap<>(2);
        header.put("typ", "JWT");
        header.put("alg", "HS256");
        //附带username和adminID生成签名
        return JWT.create().withHeader(header).withClaim("id", id)
                .withClaim("username",username).withExpiresAt(date).sign(algorithm);
    }
​
    //校验token
    public static boolean verity(String token,String password){
        try {
            Algorithm algorithm = Algorithm.HMAC256(password);
            JWTVerifier verifier = JWT.require(algorithm).build();
            verifier.verify(token);
            return true;
        } catch (IllegalArgumentException | JWTVerificationException e) {
            return false;
        }
    }
}
​
  • Config
package com.example.sport.Config;


import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import org.apache.ibatis.builder.MapperBuilderAssistant;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @program: sport
 * @description: 分页拦截器
 * @author: 左手
 * @create: 2022-01-19 15:09
 **/

@Configuration
public class MybatisConfiguration {
    @Bean
    public PaginationInterceptor paginationInterceptor() {
        // 分页配置
        PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
        return paginationInterceptor;
    }
}
  • Annotation
package com.example.sport.Annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;


/**
* @Description: 管理员Token验证注解定义
* @Param:
* @return:
* @Author: 左手
* @Date: 2022-02-13
*/
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface TokenRequired {
    boolean required() default true;
}

请求、响应拦截器

实现org.springframework.web.servletHandlerInterceptor

方法调用前提调用时间执行顺序
preHandle-Controller方法处理之前链式Intercepter情况下,Intercepter按照声明的顺序一个接一个执行若返回false,则中断执行,注意:不会进入afterCompletion
postHandlepreHandle返回trueController方法处理完之后,DispatcherServlet进行视图的渲染之前,也就是说在这个方法中你可以对ModelAndView进行操作(备注:postHandle虽然post打头,但post、get方法都能处理)链式Intercepter情况下,Intercepter按照声明的顺序倒着执行。(备注:postHandle虽然post打头,但post、get方法都能处理)
afterCompletionpreHandle返回trueDispatcherServlet进行视图的渲染之后

集成JWT的token验证


Mybatis-Plus配置


整合Redis


@Component
public class RedisUtils {

    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 读取缓存
     *
     * @param key
     * @return
     */
    public Object get(final String key) {
        return redisTemplate.opsForValue().get(key);
    }

    /**
     * 写入缓存
     */
    public boolean set( String key, Object value) {
        boolean result = false;
        try {
            redisTemplate.opsForValue().set(key, value,1, TimeUnit.DAYS);
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 更新缓存
     */
    public boolean getAndSet(final String key, String value) {
        boolean result = false;
        try {
            redisTemplate.opsForValue().getAndSet(key, value);
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 删除缓存
     */
    public boolean delete(final String key) {
        boolean result = false;
        try {
            redisTemplate.delete(key);
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

}

打包成Jar并部署到Linux

  • IDEA打包方法(Maven):
  • pom.xml中找到Java版本 (很重要)

    java的版本不对的话就容易导致项目在服务器跑不起来


VUE

常用问题

VUE 2文档

VUE 3文档

组件注册

文档

组件通信问题

  • ->

    组件模板引入初始化:

    利用引入子组件,以HTML标签中加入Prop类型来进行传递初始化参数

    文档

    调用子方法:

    <templateName ref="asd"></templateName>
    ...
    this.$ref.asd.func("123");
    

    单向数据流:

    父级 prop 的更新会向下流动到子组件中,但是反过来则不行。这样会防止从子组件意外变更父级组件的状态,从而导致你的应用的数据流向难以理解。

    额外的,每次父级组件发生变更时,子组件中所有的 prop 都将会刷新为最新的值。这意味着你应该在一个子组件内部改变 prop。如果你这样做了,Vue 会在浏览器的控制台中发出警告。

  • ->

    子组件回调:

    this.$emit(func, args);
    

    父组件接收:

    <com @func="fun"></com>
    
    <script>
    	fun(args) {
            alert(args);
        }
    </script>
    
  • Vuex的Store通用通信方法

    文档

    引入配置 main.js

    import { createApp } from 'vue'
    import { createStore } from 'vuex'
    
    // 创建一个新的 store 实例
    const store = createStore({
      state () {
        return {
          count: 0
        }
      },
      mutations: {
        increment (state) {
          state.count++
        }
      }
    })
    
    const app = createApp({ /* 根组件 */ })
    
    // 将 store 实例作为插件安装
    app.use(store)
    

    使用方法:

    // 通过 `store.state` 来获取状态对象,并通过 `store.commit` 方法触发状态变更:
    
    // 修改操作
    store.commit('increment')
    
    // 获取操作
    console.log(store.state.count) // -> 1
    
  • 路由
  • axios拦截和封装

接口测试工具

\