毕设的学习总结

小白做毕设

前端主体搭建

  • 直接用pure-design-vip生成模板

准备工作

  • springboot依赖

  • java版本的指定

毕设的学习总结_第1张图片

  • maven的指定(配置好阿里云仓库)
    毕设的学习总结_第2张图片

  • npm的配置(前提安装好依赖)

毕设的学习总结_第3张图片

  • springboot跨域配置

    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.cors.CorsConfiguration;
    import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
    import org.springframework.web.filter.CorsFilter;
    
    @Configuration
    public class CorsConfig {
    
        // 当前跨域请求最大有效时长。这里默认1天
        private static final long MAX_AGE = 24 * 60 * 60;
    
        @Bean
        public CorsFilter corsFilter() {
            UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
            CorsConfiguration corsConfiguration = new CorsConfiguration();
            corsConfiguration.addAllowedOrigin("http://localhost:8080"); // 1 设置访问源地址
            corsConfiguration.addAllowedHeader("*"); // 2 设置访问源请求头
            corsConfiguration.addAllowedMethod("*"); // 3 设置访问源请求方法
            corsConfiguration.setMaxAge(MAX_AGE);
            source.registerCorsConfiguration("/**", corsConfiguration); // 4 对接口配置跨域设置
            return new CorsFilter(source);
        }
    }
    

增删改查接口自定义实现

  • 添加配置文件application.yml

    server:
      port: 9090
    
    spring:
      datasource:
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://localhost:3306/qing?serverTimezone=GMT%2b8
        username: root
        password: 123456
    mybatis:
      mapper-locations: classpath:mapper/*.xml  #扫描所有mybatis的xml文件
      configuration:
        log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
    
    
  • 增删改查接口

    UserController.java

    package com.qingge.springboot.controller;
    
    import com.qingge.springboot.entity.User;
    import com.qingge.springboot.mapper.UserMapper;
    import com.qingge.springboot.service.UserService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.*;
    
    import java.util.List;
    
    @RestController
    @RequestMapping("/user")
    public class UserController {
    
    
        @Autowired
        private UserMapper userMapper;
    
        @Autowired
        private UserService userService;
    
        // 新增和修改
        @PostMapping
        public Integer save(@RequestBody User user) {
            // 新增或者更新
            return userService.save(user);
        }
    
        // 查询所有数据
        @GetMapping
        public List<User> index() {
            List<User> all = userMapper.findAll();
            return all;
        }
    
        @DeleteMapping("/{id}")
        public Integer delete(@PathVariable Integer id) {
            return userMapper.deleteById(id);
        }
    }
    

    UserMapper.java

    package com.qingge.springboot.mapper;
    
    import com.qingge.springboot.entity.User;
    import org.apache.ibatis.annotations.*;
    
    import java.util.List;
    
    @Mapper
    public interface UserMapper {
    
        @Select("SELECT * from sys_user")
        List<User> findAll();
    
        @Insert("INSERT into sys_user(username, password,nickname,email,phone,address) VALUES (#{username}, #{password}," +
                " #{nickname}, #{email},#{phone}, #{address})")
        int insert(User user);
    
        int update(User user);
    
        @Delete("delete from sys_user where id = #{id}")
        Integer deleteById(@Param("id") Integer id);
    
    }
    

    User.xml

    
    
    <mapper namespace="com.qingge.springboot.mapper.UserMapper">
    
        <update id="update">
            update sys_user
            <set>
                <if test="username != null">
                    username = #{username},
                if>
    
    
    
                <if test="nickname != null">
                    nickname = #{nickname},
                if>
                <if test="email != null">
                    email = #{email},
                if>
                <if test="phone != null">
                    phone = #{phone},
                if>
                <if test="address != null">
                    address = #{address}
                if>
            set>
            <where>
                id = #{id}
            where>
        update>
    
    mapper>
    

mybatis-plus集成接口

  • 根据官方文档快速入门

  • 添加mybatis-plus依赖

     
     
         com.baomidou
         mybatis-plus-boot-starter
         3.5.1
     
    
  • mybatis-plus 配置(MybatisPlusConfig.java)

    package com.qingge.springboot.config;
    
    import com.baomidou.mybatisplus.annotation.DbType;
    import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
    import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
    import org.mybatis.spring.annotation.MapperScan;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    @Configuration
    @MapperScan("com.qingge.springboot.mapper")
    public class MybatisPlusConfig {
    
        // 最新版
        @Bean
        public MybatisPlusInterceptor mybatisPlusInterceptor() {
            MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
            interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
            return interceptor;
        }
    
    }
    
    
  • 修改application.yml

    server:
      port: 9090
    
    spring:
      datasource:
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://localhost:3306/qing?serverTimezone=GMT%2b8
        username: root
        password: 123456
    mybatis:
      mapper-locations: classpath:mapper/*.xml  #扫描所有mybatis的xml文件
    #  configuration:
    #    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
    mybatis-plus:
      configuration:
        log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
    
  • User.java

    package com.qingge.springboot.entity;
    
    import com.baomidou.mybatisplus.annotation.IdType;
    import com.baomidou.mybatisplus.annotation.TableField;
    import com.baomidou.mybatisplus.annotation.TableId;
    import com.baomidou.mybatisplus.annotation.TableName;
    import com.fasterxml.jackson.annotation.JsonIgnore;
    import lombok.Data;
    
    @Data
    @TableName(value = "sys_user")
    public class User {
    
        @TableId(type = IdType.AUTO)
        private Integer id;
        private String username;
        @JsonIgnore
        private String password;
        private String nickname;
        private String email;
        private String phone;
        private String address;
    
        @TableField(value = "avatar_url")  // 指定数据库的字段名称
        private String avatar;
    
    }
    

集成swaggerui

  • 访问地址:http://localhost:9090/swagger-ui/index.html

  • SwaggerConfig.java

    package com.qingge.springboot.config;
    
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import springfox.documentation.builders.ApiInfoBuilder;
    import springfox.documentation.builders.PathSelectors;
    import springfox.documentation.builders.RequestHandlerSelectors;
    import springfox.documentation.oas.annotations.EnableOpenApi;
    import springfox.documentation.service.ApiInfo;
    import springfox.documentation.service.Contact;
    import springfox.documentation.spi.DocumentationType;
    import springfox.documentation.spring.web.plugins.Docket;
    
    @Configuration
    @EnableOpenApi
    public class SwaggerConfig {
    
    
        /**
         * 创建API应用
         * apiInfo() 增加API相关信息
         * 通过select()函数返回一个ApiSelectorBuilder实例,用来控制哪些接口暴露给Swagger来展现,
         * 本例采用指定扫描的包路径来定义指定要建立API的目录。
         *
         * @return
         */
        @Bean
        public Docket restApi() {
            return new Docket(DocumentationType.SWAGGER_2)
                    .groupName("标准接口")
                    .apiInfo(apiInfo("Spring Boot中使用Swagger2构建RESTful APIs", "1.0"))
                    .useDefaultResponseMessages(true)
                    .forCodeGeneration(false)
                    .select()
                    .apis(RequestHandlerSelectors.basePackage("com.qingge.springboot.controller"))
                    .paths(PathSelectors.any())
                    .build();
        }
    
        /**
         * 创建该API的基本信息(这些基本信息会展现在文档页面中)
         * 访问地址:http://ip:port/swagger-ui.html
         *
         * @return
         */
        private ApiInfo apiInfo(String title, String version) {
            return new ApiInfoBuilder()
                    .title(title)
                    .description("更多请关注: https://blog.csdn.net/xqnode")
                    .termsOfServiceUrl("https://blog.csdn.net/xqnode")
                    .contact(new Contact("xqnode", "https://blog.csdn.net/xqnode", "[email protected]"))
                    .version(version)
                    .build();
        }
    
    
    }
    
  • pom.xml

     
     <dependency>
         <groupId>io.springfoxgroupId>
         <artifactId>springfox-boot-starterartifactId>
         <version>3.0.0version>
     dependency>
    

前后端数据交互

vue安装axios

npm i axios -S

request.js封装

import axios from 'axios'

const request = axios.create({
    baseURL: '/api',
    timeout: 5000
})

// request 拦截器
// 可以自请求发送前对请求做一些处理
// 比如统一加token,对请求参数统一加密
request.interceptors.request.use(config => {
    config.headers['Content-Type'] = 'application/json;charset=utf-8';

    // config.headers['token'] = user.token;  // 设置请求头
    return config
}, error => {
    return Promise.reject(error)
});

// response 拦截器
// 可以在接口响应后统一处理结果
request.interceptors.response.use(
    response => {
        let res = response.data;
        // 如果是返回的文件
        if (response.config.responseType === 'blob') {
            return res
        }
        // 兼容服务端返回的字符串数据
        if (typeof res === 'string') {
            res = res ? JSON.parse(res) : res
        }
        return res;
    },
    error => {
        console.log('err' + error) // for debug
        return Promise.reject(error)
    }
)


export default request


数据请求测试

代码生成

  • mp依赖

    
    
        com.baomidou
        mybatis-plus-generator
        3.5.1
    
    
        org.apache.velocity
        velocity
        1.7
    
    
  • 代码生成 CodeGenerator

    package com.qingge.springboot.utils;
    
    import com.baomidou.mybatisplus.generator.FastAutoGenerator;
    import com.baomidou.mybatisplus.generator.config.OutputFile;
    
    import java.util.Collections;
    
    /**
     * mp代码生成器
     * by 青哥哥
     * @since 2022-01-26
     */
    public class CodeGenerator {
    
        public static void main(String[] args) {
            generate();
        }
    
        private static void generate() {
            FastAutoGenerator.create("jdbc:mysql://localhost:3306/qing?serverTimezone=GMT%2b8", "root", "123456")
                    .globalConfig(builder -> {
                        builder.author("青哥哥") // 设置作者
                                .enableSwagger() // 开启 swagger 模式
                                .fileOverride() // 覆盖已生成文件
                                .outputDir("D:\\代码\\小白做毕设2022\\springboot\\src\\main\\java\\"); // 指定输出目录
                    })
                    .packageConfig(builder -> {
                        builder.parent("com.qingge.springboot") // 设置父包名
                                .moduleName(null) // 设置父包模块名
                                .pathInfo(Collections.singletonMap(OutputFile.mapperXml, "D:\\代码\\小白做毕设2022\\springboot\\src\\main\\resources\\mapper\\")); // 设置mapperXml生成路径
                    })
                    .strategyConfig(builder -> {
                        builder.entityBuilder().enableLombok();
    //                    builder.mapperBuilder().enableMapperAnnotation().build();
                        builder.controllerBuilder().enableHyphenStyle()  // 开启驼峰转连字符
                                .enableRestStyle();  // 开启生成@RestController 控制器
                        builder.addInclude("sys_user") // 设置需要生成的表名
                                .addTablePrefix("t_", "sys_"); // 设置过滤表前缀
                    })
    //                .templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker引擎模板,默认的是Velocity引擎模板
                    .execute();
    
        }
    }
    
    
  • 模板引擎,自定义配置(controller.java.vm)

    package ${package.Controller};
    
    
    import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
    import org.springframework.web.bind.annotation.*;
    import javax.annotation.Resource;
    import java.util.List;
    import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
    
    import ${package.Service}.${table.serviceName};
    import ${package.Entity}.${entity};
    
    #if(${restControllerStyle})
    import org.springframework.web.bind.annotation.RestController;
    #else
    import org.springframework.stereotype.Controller;
    #end
    #if(${superControllerClassPackage})
    import ${superControllerClassPackage};
    #end
    
    /**
     * 

    * $!{table.comment} 前端控制器 *

    * * @author ${author} * @since ${date} */
    #if(${restControllerStyle}) @RestController #else @Controller #end @RequestMapping("#if(${package.ModuleName})/${package.ModuleName}#end/#if(${controllerMappingHyphenStyle})${controllerMappingHyphen}#else${table.entityPath}#end") #if(${kotlin}) class ${table.controllerName}#if(${superControllerClass}) : ${superControllerClass}()#end #else #if(${superControllerClass}) public class ${table.controllerName} extends ${superControllerClass} { #else public class ${table.controllerName} { #end @Resource private ${table.serviceName} ${table.entityPath}Service; // 新增或者更新 @PostMapping public boolean save(@RequestBody ${entity} ${table.entityPath}) { return ${table.entityPath}Service.saveOrUpdate(${table.entityPath}); } @DeleteMapping("/{id}") public Boolean delete(@PathVariable Integer id) { return ${table.entityPath}Service.removeById(id); } @PostMapping("/del/batch") public boolean deleteBatch(@RequestBody List<Integer> ids) { return ${table.entityPath}Service.removeByIds(ids); } @GetMapping public List<${entity}> findAll() { return ${table.entityPath}Service.list(); } @GetMapping("/{id}") public ${entity} findOne(@PathVariable Integer id) { return ${table.entityPath}Service.getById(id); } @GetMapping("/page") public Page<${entity}> findPage(@RequestParam Integer pageNum, @RequestParam Integer pageSize) { QueryWrapper<User> queryWrapper = new QueryWrapper<>(); queryWrapper.orderByDesc("id"); return ${table.entityPath}Service.page(new Page<>(pageNum, pageSize), queryWrapper); } } #end

前端讲解

前端不是后端程序员重点,可copy我们的练手项目使用

导入导出接口实现

  • 利用hutool工具实现(功能强大)https://www.hutool.cn/docs/#/poi/Excel%E5%B7%A5%E5%85%B7-ExcelUtil

  • pom依赖

    
        cn.hutool
        hutool-all
        5.7.20
    
     
         org.apache.poi
         poi-ooxml
         4.1.2
     
    
  • 导出接口 起别名可在实体类用@Alias实现

    /**
         * 导出接口
         */
        @GetMapping("/export")
        public void export(HttpServletResponse response) throws Exception {
            // 从数据库查询出所有的数据
            List<User> list = userService.list();
            // 通过工具类创建writer 写出到磁盘路径
    //        ExcelWriter writer = ExcelUtil.getWriter(filesUploadPath + "/用户信息.xlsx");
            // 在内存操作,写出到浏览器
            ExcelWriter writer = ExcelUtil.getWriter(true);
            //自定义标题别名
            writer.addHeaderAlias("username", "用户名");
            writer.addHeaderAlias("password", "密码");
            writer.addHeaderAlias("nickname", "昵称");
            writer.addHeaderAlias("email", "邮箱");
            writer.addHeaderAlias("phone", "电话");
            writer.addHeaderAlias("address", "地址");
            writer.addHeaderAlias("createTime", "创建时间");
            writer.addHeaderAlias("avatarUrl", "头像");
    
            // 一次性写出list内的对象到excel,使用默认样式,强制输出标题
            writer.write(list, true);
    
            // 设置浏览器响应的格式
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8");
            String fileName = URLEncoder.encode("用户信息", "UTF-8");
            response.setHeader("Content-Disposition", "attachment;filename=" + fileName + ".xlsx");
    
            ServletOutputStream out = response.getOutputStream();
            writer.flush(out, true);
            out.close();
            writer.close();
    
        }
    
  • 导入接口

    /**
         * excel 导入
         * @param file
         * @throws Exception
         */
        @PostMapping("/import")
        public Boolean imp(MultipartFile file) throws Exception {
            InputStream inputStream = file.getInputStream();
            ExcelReader reader = ExcelUtil.getReader(inputStream);
            // 方式1:(推荐) 通过 javabean的方式读取Excel内的对象,但是要求表头必须是英文,跟javabean的属性要对应起来
    //        List list = reader.readAll(User.class);
    
            // 方式2:忽略表头的中文,直接读取表的内容
            List<List<Object>> list = reader.read(1);
            List<User> users = CollUtil.newArrayList();
            for (List<Object> row : list) {
                User user = new User();
                user.setUsername(row.get(0).toString());
                user.setPassword(row.get(1).toString());
                user.setNickname(row.get(2).toString());
                user.setEmail(row.get(3).toString());
                user.setPhone(row.get(4).toString());
                user.setAddress(row.get(5).toString());
                user.setAvatarUrl(row.get(6).toString());
                users.add(user);
            }
    
            userService.saveBatch(users);
            return true;
        }
    
  • vue导入

    
      导入 
    
    
    
    handleExcelImportSuccess() {
        this.$message.success("导入成功")
        this.load()
    }
    
  • vue导出

    导出 
    
    exp() {
    	window.open("http://localhost:9090/user/export")
    }
    

各接口的实现

不再一一列出,看源码接口实现

统一异常处理,包装类

  • Result.java

    package com.qingge.springboot.common;
    
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    
    /**
     * 接口统一返回包装类
     */
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public class Result {
    
        private String code;
        private String msg;
        private Object data;
    
        public static Result success() {
            return new Result(Constants.CODE_200, "", null);
        }
    
        public static Result success(Object data) {
            return new Result(Constants.CODE_200, "", data);
        }
    
        public static Result error(String code, String msg) {
            return new Result(code, msg, null);
        }
    
        public static Result error() {
            return new Result(Constants.CODE_500, "系统错误", null);
        }
    
    }
    
    
  • 全局异常处理类(GlobalExceptionHandler.java)

    package com.qingge.springboot.exception;
    
    import com.qingge.springboot.common.Result;
    import org.springframework.web.bind.annotation.ControllerAdvice;
    import org.springframework.web.bind.annotation.ExceptionHandler;
    import org.springframework.web.bind.annotation.ResponseBody;
    
    @ControllerAdvice
    public class GlobalExceptionHandler {
    
        /**
         * 如果抛出的的是ServiceException,则调用该方法
         * @param se 业务异常
         * @return Result
         */
        @ExceptionHandler(ServiceException.class)
        @ResponseBody
        public Result handle(ServiceException se){
            return Result.error(se.getCode(), se.getMessage());
        }
    
    }
    
    
  • 自定义异常类(ServiceException.java)

    package com.qingge.springboot.exception;
    
    import lombok.Getter;
    
    /**
     * 自定义异常
     */
    @Getter
    public class ServiceException extends RuntimeException {
        private String code;
    
        public ServiceException(String code, String msg) {
            super(msg);
            this.code = code;
        }
    
    }
    
    

JWT

JWT依赖

 
 
     com.auth0
     java-jwt
     3.10.3
 

TokenUtils.java

package com.qingge.springboot.utils;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.qingge.springboot.entity.User;
import com.qingge.springboot.service.IUserService;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Date;

@Component
public class TokenUtils {

    private static IUserService staticUserService;

    @Resource
    private IUserService userService;

    @PostConstruct
    public void setUserService() {
        staticUserService = userService;
    }

    /**
     * 生成token
     *
     * @return
     */
    public static String genToken(String userId, String sign) {
        return JWT.create().withAudience(userId) // 将 user id 保存到 token 里面,作为载荷
                .withExpiresAt(DateUtil.offsetHour(new Date(), 2)) // 2小时后token过期
                .sign(Algorithm.HMAC256(sign)); // 以 password 作为 token 的密钥
    }

    /**
     * 获取当前登录的用户信息
     *
     * @return user对象
     */
    public static User getCurrentUser() {
        try {
            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
            String token = request.getHeader("token");
            if (StrUtil.isNotBlank(token)) {
                String userId = JWT.decode(token).getAudience().get(0);
                return staticUserService.getById(Integer.valueOf(userId));
            }
        } catch (Exception e) {
            return null;
        }
        return null;
    }
}

token示例

{"username":"admin","password":"admin","nickname":"管理员11111","avatarUrl":"https://img-blog.csdnimg.cn/c6d0ece75d3f4833bd820b8aa2eb952b.png","token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiIxIiwiZXhwIjoxNjQ0MzgxMDI4fQ.87nwS8ENDOu6RY-4PTLBBzXfDv6-5TiQLQhBXrYGb700"}

JwtInterceptor.java

package com.qingge.springboot.config.interceptor;

import cn.hutool.core.util.StrUtil;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.qingge.springboot.common.Constants;
import com.qingge.springboot.entity.User;
import com.qingge.springboot.exception.ServiceException;
import com.qingge.springboot.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class JwtInterceptor implements HandlerInterceptor {

    @Autowired
    private IUserService userService;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        String token = request.getHeader("token");
        // 如果不是映射到方法直接通过
        if(!(handler instanceof HandlerMethod)){
            return true;
        }
        // 执行认证
        if (StrUtil.isBlank(token)) {
            throw new ServiceException(Constants.CODE_401, "无token,请重新登录");
        }
        // 获取 token 中的 user id
        String userId;
        try {
            userId = JWT.decode(token).getAudience().get(0);
        } catch (JWTDecodeException j) {
            throw new ServiceException(Constants.CODE_401, "token验证失败,请重新登录");
        }
        // 根据token中的userid查询数据库
        User user = userService.getById(userId);
        if (user == null) {
            throw new ServiceException(Constants.CODE_401, "用户不存在,请重新登录");
        }
        // 用户密码加签验证 token
        JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(user.getPassword())).build();
        try {
            jwtVerifier.verify(token); // 验证token
        } catch (JWTVerificationException e) {
            throw new ServiceException(Constants.CODE_401, "token验证失败,请重新登录");
        }
        return true;
    }
}

InterceptorConfig.java

package com.qingge.springboot.config;

import com.qingge.springboot.config.interceptor.JwtInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class InterceptorConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(jwtInterceptor())
                .addPathPatterns("/**")  // 拦截所有请求,通过判断token是否合法来决定是否需要登录
                .excludePathPatterns("/user/login", "/user/register", "/**/export", "/**/import");
    }

    @Bean
    public JwtInterceptor jwtInterceptor() {
        return new JwtInterceptor();
    }

}

login方法

@Override
public UserDTO login(UserDTO userDTO) {
    User one = getUserInfo(userDTO);
    if (one != null) {
    BeanUtil.copyProperties(one, userDTO, true);
    // 设置token
    String token = TokenUtils.genToken(one.getId().toString(), one.getPassword());
    userDTO.setToken(token);
    return userDTO;
    } else {
    throw new ServiceException(Constants.CODE_600, "用户名或密码错误");
    }
}

request.js

  let user = localStorage.getItem("user") ? JSON.parse(localStorage.getItem("user")) : null
    if (user) {
        config.headers['token'] = user.token;  // 设置请求头
    }

 // 当权限验证不通过的时候给出提示
        if (res.code === '401') {
            ElementUI.Message({
                message: res.msg,
                type: 'error'
            });
        }

文件上传

接口实现看源码

application.yml

files:
  upload:
    path: D:\大二下学期\小白做毕设\files\

配置拦截器,不需要拦截

前端实现

图标实现

vue安装echarts

npm i echarts -S

Echarts官网:https://echarts.apache.org/zh/index.html

Echarts使用手册:https://echarts.apache.org/handbook/zh/get-started/

引入echarts:import * as echarts from 'echarts'

前端实现看源码

权限菜单讲解

角色管理页面

  • 设计sys_role表
  • 用代码生成器生成三层架构
  • 复制拷贝一份Role.vue (记得增加路由,修改响应字段、功能,使接口一致)

菜单管理页面

  • 设计sys_menu表
  • 用代码生成器生成三层架构
  • 复制拷贝一份Menu.vue (记得增加路由,修改响应字段、功能,使接口一致)

Unknown column ‘icon’ in ‘field list’ 报错原因是数据库字段不一致,重修修改数据库字段

分配菜单功能

  • Role.vue 添加分配菜单按钮

  • 在菜单分配表格使用树形控件

  • 修改Menu.vue,使用树形表格(需要用到children,要修改对应entity对象,添加children属性,同时加上@TableFild(exist=false))

     	@TableField(exist = false)
          private List<Menu> children;
          
          @TableField("pid")
          private Integer pid;
    
  • 修改接口,填充children,所以要修改数据库字段,利用id-pid的自关联的关系

    @GetMapping
        public Result findAll(@RequestParam(defaultValue = "") String name) {
            QueryWrapper<Menu> queryWrapper = new QueryWrapper<>();
            if(StrUtil.isNotBlank(name)){
                queryWrapper.like("name",name);
            }
            //查询所有菜单
            List<Menu> list = menuService.list(queryWrapper);
            //查询父菜单
            List<Menu> parentMenu = list.stream().filter(menu -> (menu.getPid() == null)).collect(Collectors.toList());
            for (Menu menu : parentMenu) {
                //为每个父菜单封装二级菜单
                List<Menu> childrenList = list.stream().filter(m -> menu.getId().equals(m.getPid())).collect(Collectors.toList());
                menu.setChildren(childrenList);
            }
            return Result.success(parentMenu);
        }
    
  • 修改前端页面去掉分页,添加新增子菜单功能

    新增子菜单
    
    handleAdd(pid) {
          this.dialogFormVisible = true;
          this.form = {};
          this.form.pid=pid;
        },
    
    save() {
          // console.log(this.form);
          request.post("menu", this.form).then(res => {
            if (res.code=='200') {
              this.$message.success("保存成功");
              this.dialogFormVisible = false;
              this.load();
            } else {
              this.$message.error("保存失败");
            }
          })
        },
    
  • 修改Role.vue的分配菜单,调用接口数据,记得加上prop属性才能显示数据

  • 完善图标功能显示,新建Dict字典表(name,value,type) 新建entity,mapper

  • 新建接口(查询dict表中所有的icon类型)

    @GetMapping("/icons")
        public Result icons() {
            QueryWrapper<Dict> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("type", Constants.DICT_TYPE_ICON);
            List<Dict> dictList = this.dictMapper.selectList(queryWrapper);
            return Result.success(dictList);
        }
    
  • Menu.vue 前端下拉框的实现,表格中图标的显示

    
                      
                        
                          {{item.name}}
                        
                      
                  
    
     
                  
                
    
  • Role.vue 分配菜单中图标的添加,以及菜单的默认展开功能

    
                
                   {{ data.name }}
                
                
    
    handleMenu(){
          this.menuVisible=true;
          this.request.get("menu").then(res=>{
            this.treeData=res.data;
            this.expanded=res.data.map(v=>v.id);
          })
        }
    
  • 新建角色菜单关系表sys_role_menu(role_id,menu_id)新建实体类,mapper

  • 写两个接口,先删后增 关于role_menu实体类的增删与查

    @GetMapping("roleMenu/{roleId}")
        public List<Integer> findMenuIdByRoleId(@PathVariable("roleId") Integer roleId) {
            return roleService.findMenuIdByRoleId(roleId);
        }
    @PostMapping("roleMenu/{roleId}")
        public Result addMenu(@PathVariable("roleId")Integer roleId,@RequestBody List<Integer> menuIds){
             roleService.addMenu(roleId,menuIds);
             return Result.success();
        }
    
    @Select("select menu_id from sys_role_menu where role_id=#{roleId}")
        List<Integer> findMenuIdByRoleId(@Param("roleId") Integer roleId);
    
    @Override
        public void addMenu(Integer roleId, List<Integer> menuIds) {
            LambdaQueryWrapper<RoleMenu> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(RoleMenu::getRoleId,roleId);
            roleMenuMapper.delete(queryWrapper);
            for (Integer menuId : menuIds) {
                RoleMenu roleMenu = new RoleMenu();
                roleMenu.setMenuId(menuId);
                roleMenu.setRoleId(roleId);
                roleMenuMapper.insert(roleMenu);
            }
        }
    
  • 前端调用,修改树形控件传参数(role_id,Listmenu_id)实现新增关系和菜单默认选择功能


            
               {{ data.name }}
            
            

 handleMenu(id){
      this.menuVisible=true;
      this.request.get("menu").then(res=>{
        this.treeData=res.data;
        this.expanded=res.data.map(v=>v.id);
      })
      this.roleId=id;
      this.request.get("role/roleMenu/"+this.roleId).then(res=>{
        this.checked=res;
      })
    },

saveRoleMenu(){
      this.request.post("role/roleMenu/"+this.roleId,this.$refs.tree.getCheckedKeys()).then(res=>{
        if(res.code=='200'){
          this.$message.success("绑定成功");
          this.menuVisible=false;
        }
      })
    }
  • 修改数据库user表(role) role表(flag)对应实体类也要进行修改

  • 前端User.vue界面表格与表单填加角色信息显示和添加功能,Role.vue添加标识编辑与显示

    
                
    
    
                    
                      
                      
                    
                  
    
    this.request.get("role").then(res=>{
          this.options=res;
        })
    
  • 修改UserDto对象(role,List

    )完善登录接口

     public Result login(UserDto userDto) {
            User user = getUserInfo(userDto);
            if(user==null){
                throw new ServiceException(Constants.CODE_600,"用户名或密码错误");
            }
            BeanUtils.copyProperties(user,userDto);
            //menus属性填充
            String roleFlag = userDto.getRole(); // ROLE_ADMIN
            List<Menu> roleMenu = getRoleMenu(roleFlag);
            userDto.setMenus(roleMenu);
    
            String token = TokenUtils.createToken(user.getId().toString(), user.getPassword());
            userDto.setToken(token);
            return Result.success(userDto);
        }
    
    private List<Menu> getRoleMenu(String roleFlag){
            QueryWrapper<Role> queryWrapper=new QueryWrapper<>();
            queryWrapper.eq("flag",roleFlag);
            Integer roleId = roleMapper.selectOne(queryWrapper).getId();
            List<Integer> menuIds = roleMenuMapper.findMenuIdByRoleId(roleId);
            //调用menuService查询所有菜单
            List<Menu> allMenu = menuService.findAllMenu("");
            // new一个最后筛选完成之后的list
            List<Menu> result=new ArrayList<>();
            // 筛选当前用户角色的菜单
            for (Menu menu : allMenu) {
                if(menuIds.contains(menu.getId())){
                    result.add(menu);
                }
                List<Menu> children = menu.getChildren();
                // removeIf()  移除 children 里面不在 menuIds集合中的 元素
                children.removeIf(child->!menuIds.contains(child.getId()));
            }
            return result;
        }
    
  • 修改Aside.vue实现动态菜单

    Aside.vue

{{ item.name }}
{{ subItem.name }}
data(){ return { menus:localStorage.getItem("menus")?JSON.parse(localStorage.getItem("menus")):[] } },

Login.vue

login(){
      this.$refs['userForm'].validate((valid)=>{
        if(valid){//表单校验合法
          this.request.post("user/login",this.user).then(res=>{
            if(!res.data){
              this.$message.error(res.msg);
            }else{
              this.$router.push("/");
              localStorage.setItem("user",JSON.stringify(res.data));
              localStorage.setItem("menus",JSON.stringify(res.data.menus));
              this.$message.success("登录成功");
            }
          })
        }else{
          return false;
        }
      })
    }
  • 修改sys_menu(page_path) 修改实体类 前端页面Menu.vue表格与表单显示页面路径

  • 修改router/index.js 实现动态路由,在login.vue动态设置路由 我实现不了

    // 注意:刷新页面会导致页面路由重置
    export const setRoutes = () => {
      console.log(router.getRoutes())
      const storeMenus = localStorage.getItem("menus");
      if (storeMenus) {
    
        // 获取当前的路由对象名称数组
        const currentRouteNames = router.getRoutes().map(v => v.name);
        if (!currentRouteNames.includes('Manage')) {
          // 拼装动态路由
          const manageRoute = { path: '/', name: 'Manage', component: () => import('../views/Manage.vue'), redirect: "/home", children: [
              { path: 'person', name: '个人信息', component: () => import('../views/Person.vue')},
              // { path: 'password', name: '修改密码', component: () => import('../views/Password.vue')}
            ] }
          const menus = JSON.parse(storeMenus)
          menus.forEach(item => {
            if (item.url) {  // 当且仅当path不为空的时候才去设置路由
              let itemMenu = { path: item.url.replace("/", ""), name: item.name, component: () => import('../views/' + item.pagePath + '.vue')}
              manageRoute.children.push(itemMenu)
            } else if(item.children.length) {
              item.children.forEach(item => {
                if (item.url) {
                  let itemMenu = { path: item.url.replace("/", ""), name: item.name, component: () => import('../views/' + item.pagePath + '.vue')}
                  manageRoute.children.push(itemMenu)
                }
              })
            }
          })
          // 动态添加到现在的路由对象中去
          router.addRoute(manageRoute)
        }
    
      }
    }
    
    setRoutes();
    
  • 实现404页面

    
    
    
    
    
    
    
    const routes = [
        {
        path: '/*'
        name: '404',
        component: () => import(/* webpackChunkName: "about" */ '../views/404.vue')
      }
    ]
    
  • 修改添加二级菜单没有一级菜单的bug 在添加的实现中进行二级判断,额外把父菜单也插入进去

    public void setRoleMenu(Integer roleId, List<Integer> menuIds) {
    //        QueryWrapper queryWrapper = new QueryWrapper<>();
    //        queryWrapper.eq("role_id", roleId);
    //        roleMenuMapper.delete(queryWrapper);
    
            // 先删除当前角色id所有的绑定关系
            roleMenuMapper.deleteByRoleId(roleId);
    
            // 再把前端传过来的菜单id数组绑定到当前的这个角色id上去
            List<Integer> menuIdsCopy = CollUtil.newArrayList(menuIds);
            for (Integer menuId : menuIds) {
                Menu menu = menuService.getById(menuId);
                if (menu.getPid() != null && !menuIdsCopy.contains(menu.getPid())) { // 二级菜单 并且传过来的menuId数组里面没有它的父级id
                    // 那么我们就得补上这个父级id
                    RoleMenu roleMenu = new RoleMenu();
                    roleMenu.setRoleId(roleId);
                    roleMenu.setMenuId(menu.getPid());
                    roleMenuMapper.insert(roleMenu);
                    menuIdsCopy.add(menu.getPid());
                }
                RoleMenu roleMenu = new RoleMenu();
                roleMenu.setRoleId(roleId);
                roleMenu.setMenuId(menuId);
                roleMenuMapper.insert(roleMenu);
            }
        }
    
  • 在store/index.js 实现注销方法在管理员分配菜单后触发,重新登录

    const store = new Vuex.Store({
        state: {
            currentPathName: ''
        },
        mutations: {
            setPath (state) {
                state.currentPathName = localStorage.getItem("currentPathName")
            },
            logout(){
                localStorage.removeItem("user");
                localStorage.removeItem("menus");
                router.push("/login")
            }
        }
    })
    
     handleMenu(role){
          this.menuVisible=true;
          this.request.get("menu").then(res=>{
            this.treeData=res.data;
            this.expanded=res.data.map(v=>v.id);
          })
          this.roleId=role.id;
          this.roleFlag=role.flag;
          this.request.get("role/roleMenu/"+this.roleId).then(res=>{
            this.checked=res;
          })
        },
    
    saveRoleMenu(){
    
          this.request.post("role/roleMenu/"+this.roleId,this.$refs.tree.getCheckedKeys()).then(res=>{
            if(res.code=='200'){
              this.$message.success("绑定成功");
              this.menuVisible=false;
              if(this.roleFlag==="SYS_ADMIN"){
                this.$store.commit("logout");
              }
            }
          })
          // console.log( this.$refs.tree.getCheckedNodes().map(v=>v.id));
        }
    
    
  • 修改bug:一级菜单选中后全选中二级菜单

    handleMenu(role){
          this.menuVisible=true;
          this.request.get("menu").then(res=>{
            this.treeData=res.data;
            this.expanded=res.data.map(v=>v.id);
          })
          this.roleId=role.id;
          this.roleFlag=role.flag;
          this.request.get("role/roleMenu/"+this.roleId).then(res=>{
            this.checked=res;
            this.ids.forEach(id=>{
              if(!this.checked.includes(id)){
                this.$nextTick(() => {
                  this.$refs.tree.setChecked(id, false)
                })
              }
            })
          })
        },
            
            this.request.get("menu/ids").then(res=>{
          this.ids=res.data;
        })
    
    //要额外写个查询所有菜单id的接口
    
    public Result getAllMenu() {
            List<Menu> list = list();
    //        List ids=new ArrayList<>();
    //        for (Menu menu : list) {
    //            Integer id=menu.getId();
    //            ids.add(id);
    //        }
            List<Integer> ids = list.stream().map(menu -> menu.getId()).collect(Collectors.toList());
            return Result.success(ids);
    
            
        }
    
    
  • 修改bug:一登录直接404 配置路由守卫

    {
        path: '/404',
        name: '404',
        component: () => import('../views/404.vue')
      },
    
    
    router.beforeEach((to, from, next) => {
      localStorage.setItem("currentPathName", to.name)  // 设置当前的路由名称
      store.commit("setPath")
    
      // 未找到路由的情况
      if (!to.matched.length) {
        const storeMenus = localStorage.getItem("menus")
        if (storeMenus) {
          next("/404")
        } else {
          // 跳回登录页面
          next("/login")
        }
      }
      // 其他的情况都放行
      next()
    
    })
    
  • 修改bug: 个人信息、修改密码的404 设置固定路由

    let managerRoute = {path: '/', name: 'Manager',component: () => import('../views/Manage'), redirect: "/home",children: [
             { path: 'person', name: '个人信息', component: () => import('../views/Person.vue')},
             // { path: 'password', name: '修改密码', component: () => import('../views/Password.vue')},
    
  • 修改bug:对于未来元素(还没出现的元素)进行方法调用 1.调整代码顺序,先渲染未来元素再进行对未来元素的方法调用,2. 使用$nextTick处理未来元素,等到这个元素渲染完成之后,再去使用它

    selectMenu(role) {
          this.roleId = role.id
          this.roleFlag = role.flag
    
          // 请求菜单数据
          this.request.get("/menu").then(res => {
            this.menuData = res.data
    
            // 把后台返回的菜单数据处理成 id数组
            this.expends = this.menuData.map(v => v.id)
          })
    
          this.request.get("/role/roleMenu/" + this.roleId).then(res => {
            this.checks = res.data
           // this.menuDialogVis = true
            this.ids.forEach(id => {
              if (!this.checks.includes(id)) {
                // 可能会报错:Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'setChecked')
                this.$nextTick(() => {
                  this.$refs.tree.setChecked(id, false)
                })
              }
            })
            this.menuDialogVis = true
          })
        },
      }
    
  • 修改bug:给管理员新添页面,配菜菜单分配跳到登录后,进新页面报404 提供重置路由想法,让其能再去添加路由

    // 提供一个重置路由的方法
    export const resetRouter = () => {
      router.matcher = new VueRouter({
        mode: 'history',
        base: process.env.BASE_URL,
        routes
      })
    }
    //登录的时候调用调用这个接口
    

服务器部署

  • 购买阿里云服务器

  • 重置密码

  • 安装X-shell7远程连接工具,新建会话连接

  • 查看服务器配置(free -h,df -h,top)

  • 开启端口号(安全组)9090、80、3306

  • 服务器中安装软件,安装xftp传输(/home/package)jdk,nginx

  • 利用部署笔记,有道云笔记 安装docker

  • 利用docker安装mysql,在本机Navicat新建连接服务器的数据库

  • 项目修改配置,打包到服务器 要改数据库连接url的ip(用外网ip)

  • 授权mysql,刷新授权

  • 启动服务器中的jar包,测试访问 http://39.108.128.26:9090/swagger-ui/index.html#/

  • 令jar包后台部署

    nohup java -jar springboot-0.0.1-SNAPSHOT.jar &
    
    ps -ef | grep java 后台查询java进程
    
    kill -9 [进程号] 关闭后台进程
    
  • 安装 anywhere前端静态资源服务器插件;启动dist目录中的前端项目

    npm install anywhere -g
    
  • 安装nginx(根据笔记安装) 根据服务器ip输入测试nginx安装是否成功(80端口要打开)

  • 配置nginx vue /dist 重启nginx

    location / {
                root /home/server/dist;
                index index.html index.htm;
                try_files $uri $uri/ /index.html;
            }
    
    ./nginx -s reload
    
  • 前端上传和导出localhost修改成服务器外网ip

    :action="'http://'+serverIp+':9090/'"
    
  • 后台配置同样配置serverIp 文件上传,导出,接口的使用都需要公网iP

  • 重新打包,重新后台启动

    先kill,在重新启动
    
    tailf nohup.out(查看后台日志)
    
    npm run build (前端打dist包)
    
    cd /usr/local/nginx/sbin
    ./niginx -s reload 重启nginx
    
  • 申请备案获取自己域名,若是本地访问可以修改C:windows\system32\drivers\etc\hosts 后面加ip地址,加网址

  • 常用命令

    chmod 777 文件名 --- 修改文件权限
    
    ps -ef | grep java 后台查询
    

实现一对一,一对多,多对多的关联查询

  • 添加课程表course(id,name,score,times-varchar,state-tinyint -1,teacher_id)

  • 直接代码生成

  • 角色修改,生成Course.vue前端页面(可以使用生成器)

  • 写课表对应老师的功能 (多表查询)

    @GetMapping("/page")
        public Result findPage(@RequestParam(defaultValue = "") String name,
                               @RequestParam Integer pageNum,
                               @RequestParam Integer pageSize) {
    //        QueryWrapper queryWrapper = new QueryWrapper<>();
    //        queryWrapper.orderByDesc("id");
    //        if (!"".equals(name)) {
    //            queryWrapper.like("name", name);
    //        }
            return Result.success(courseService.findPage(new Page<>(pageNum, pageSize), name));
        }
        
            public Page<Course> findPage(Page<Course> coursePage,String name) {
    //        Page page = page(coursePage, queryWrapper);
    //        List courseList = page.getRecords();
    //        for (Course course : courseList) {
    //            course.setTeacher(userService.getById(course.getTeacherId()).getNickname());
    //        }
    //        return page;
            return courseMapper.findPage(coursePage,name);
        }
        
        Page<Course> findPage(Page<Course> coursePage, @RequestParam("name") String name);
    
    <select id="findPage" resultType="com.qingge.springboot.entity.Course">
            SELECT course.* , user.nickname as teacher
            FROM `sys_course` course
            LEFT JOIN sys_user user
            on course.teacher_id=user.id
            <where>
                <if test="name!=null and name !=''">
                    and  name like concat('%',#{name},'%')
                if>
            where>
        select>
    
  • 老师教授的课程显示按钮,表格文字加el-tag

    @GetMapping("/teacherId/{teacherId}")
        public Result findCourseByTeacherId(@PathVariable("teacherId") Integer teacherId){
            QueryWrapper<Course> queryWrapper=new QueryWrapper<>();
            queryWrapper.eq("teacher_id",teacherId);
            List<Course> result = courseService.list(queryWrapper);
            return Result.success(result);
        }
        
    
    教授课程 
    
    
          
            
            
            
          
        
        
        handleCourse(teacherId){
          this.courseVis=true;
          this.request.get("/course/teacherId/"+teacherId).then(res=>{
            this.courseData=res.data;
          })
        }
    
  • 学生选课功能实现(建立多对多关系表,写接口,写前台)

    @GetMapping("saveStudentCourse/{studentId}/{courseId}")
        public Result saveStudentCourse(@PathVariable("studentId")Integer studentId,@PathVariable("courseId")Integer courseId){
            courseService.saveStudentCourse(studentId,courseId);
            return Result.success();
        }
    
    @Override
        @Transactional
        public void saveStudentCourse(Integer studentId, Integer courseId) {
            courseMapper.deleteStudentCourse(studentId,courseId);
            courseMapper.saveStudentCourse(studentId,courseId);
        }
    
    <insert id="saveStudentCourse">
            insert into student_course values(#{studentId},#{courseId})
    
        </insert>
        <delete id="deleteStudentCourse">
            delete  from student_course where student_id=#{studentId} and course_id=#{courseId}
        </delete>
    
    handleSaveCourse(course){
          if(!course.state){
            this.$message.error("该课程暂时无法选择");
            return;
          }
          let studentId=this.user.id;
          this.request.get("/course/saveStudentCourse/"+studentId+"/"+course.id).then(res=>{
            if (res.code === '200') {
              this.$message.success("选课成功")
              this.load()
            } else {
              this.$message.error("选课失败")
            }
          })
        },
    
  • 实现我的课程查看

    @GetMapping("/studentCourse/{studentId}")
        public Result findCourseByStudentId(@PathVariable("studentId") Integer studentId){
            List<Course> result=courseService.findCourseByStudentId(studentId);
            return Result.success(result);
        }
    
    @Override
        public List<Course> findCourseByStudentId(Integer studentId) {
            List<Course> courseList = courseMapper.findCourseByStudentId(studentId);
            for (Course course : courseList) {
                Integer teacherId = course.getTeacherId();
                User teacher = userMapper.selectById(teacherId);
                course.setTeacher(teacher.getNickname());
            }
            return courseList;
        }
    
     <select id="findCourseByStudentId" resultType="com.qingge.springboot.entity.Course">
            SELECT course.*
            from sys_course course
                     LEFT JOIN student_course sc
                               on sc.course_id=course.id
                     LEFT JOIN sys_user user
                               on sc.student_id=user.id
            WHERE sc.student_id=#{studentId}
        </select>
    
    我的课程 
    
    
          
            
            
            
            
          
        
    
    handleMyCourse(){
          let studentId=this.user.id;
          this.request.get("/course/studentCourse/"+studentId).then(res=>{
            this.myCourseVis=true;
            this.courseData=res.data;
          })
        }
    

前台主页实现

  • 前台布局,页面的实现

  • 跳转路由问题

  • 特殊接口不用权限(自定义注解实现)

    
    @Target({ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface AuthAccess {
    }
    
    
    if(!(handler instanceof HandlerMethod)){
                return true;
            }else{
                AuthAccess authAccess = ((HandlerMethod) handler).getMethodAnnotation(AuthAccess.class);
                if(authAccess!=null){
                    return  true;
                }
            }
    

springboot集成redis做缓存

  • 添加依赖(springboot-cache)

     
                org.springframework.boot
                spring-boot-starter-cache
            
    
  • 添加注解,实现spring cache的集成使用(可根据博客食用)

     @PostMapping("/update")
        @CachePut(value = "files", key = "'frontAll'")
        public Result update(@RequestBody Files files) {
            fileMapper.updateById(files);
            return Result.success(fileMapper.selectList(null));
    
        }
    
        @DeleteMapping("/{id}")
        @CacheEvict(value="files",key="'frontAll'")
        public Result delete(@PathVariable Integer id) {
            Files files = fileMapper.selectById(id);
            files.setIsDelete(true);
            fileMapper.updateById(files);
            return Result.success();
        }
    
    @GetMapping("findAll")
        @Cacheable(value = "files" ,key = "'frontAll'")
        public Result findAll(){
            List<Files> filesList = fileMapper.selectList(null);
            return Result.success(filesList);
        }
    
  • 添加依赖(springboot-redis)

    
                org.springframework.boot
                spring-boot-starter-redis
                1.4.7.RELEASE
            
    
  • 增加配置,使用redis

    public Result findAll(){
            String  str = (String) redisTemplate.opsForValue().get(Constants.REDIS_KEY);
            List<Files> filesList;
            if(str!=null){
                filesList = JSONUtil.toBean(str, new TypeReference<List<Files>>() {
                }, true);
            }else{
                filesList = fileMapper.selectList(null);
                String jsonStr = JSONUtil.toJsonStr(filesList);
                redisTemplate.opsForValue().set(Constants.REDIS_KEY,jsonStr,30,TimeUnit.MINUTES);
            }
    
            return Result.success(filesList);
        }
    
    
    //清空缓存
    public void flushRedis(String key){
            redisTemplate.delete(key);
        }
    

百度地图集成

根据官方文档学习是最好的

  • 申请key值

  • Hello Word

  • 点标记

      //定义事件处理方法
      var clickHandler=function(evt){
        var lat = evt.latLng.getLat().toFixed(6);
        var lng = evt.latLng.getLng().toFixed(6);
        console.log("您点击的的坐标是:"+ lat + "," + lng);
      }
    //Map实例创建后,通过on方法绑定点击事件
      map.on("click",clickHandler)
    
    var markerLayer = new TMap.MultiMarker({
        map: map,  //指定地图容器
        //样式定义
        styles: {
          //创建一个styleId为"myStyle"的样式(styles的子属性名即为styleId)
          "myStyle": new TMap.MarkerStyle({
            "width": 25,  // 点标记样式宽度(像素)
            "height": 35, // 点标记样式高度(像素)
    
          })
        },
        //点标记数据数组
        geometries: [{
          "id": "1",   //点标记唯一标识,后续如果有删除、修改位置等操作,都需要此id
          "styleId": 'myStyle',  //指定样式id
          "position": new TMap.LatLng(23.040630,113.370344),  //点标记坐标位置
        },
          {
            "id": "2",   //点标记唯一标识,后续如果有删除、修改位置等操作,都需要此id
            "styleId": 'myStyle',  //指定样式id
            "position": new TMap.LatLng(23.041616,113.372654),  //点标记坐标位置
          }
        ]
      });
    
  • 折线

    //创建 MultiPolyline
      var polylineLayer = new TMap.MultiPolyline({
        id: 'polyline-layer', //图层唯一标识
        map: map,//设置折线图层显示到哪个地图实例中
        //折线样式定义
        styles: {
          'style_blue': new TMap.PolylineStyle({
            'color': '#3777FF', //线填充色
            'width': 6, //折线宽度
            'borderWidth': 5, //边线宽度
            'borderColor': '#FFF', //边线颜色
            'lineCap': 'butt' //线端头方式
          }),
          'style_red': new TMap.PolylineStyle({
            'color': '#CC0000', //线填充色
            'width': 6, //折线宽度
            'borderWidth': 5, //边线宽度
            'borderColor': '#CCC', //边线颜色
            'lineCap': 'round' //线端头方式
          })
        },
        //折线数据定义
        geometries: [
          {//第1条线
            'id': 'pl_1',//折线唯一标识,删除时使用
            'styleId': 'style_blue',//绑定样式名
            'paths': [new TMap.LatLng(23.040630,113.370344), new TMap.LatLng(23.041616,113.372654)]
          },
        ]
      });
    
  • 信息窗口

    //创建InfoWindow实例,并进行初始化
      var infowindow=new TMap.InfoWindow({
        content:"
    广州大学
    "
    , //信息窗口内容 position:new TMap.LatLng(23.040630,113.370344),//显示信息窗口的坐标 map:map }); infowindow.close(); markerLayer.on("click", function () { //设置infoWindow infowindow.open(); //打开信息窗 })

Vue集成视频播放

  • 修改上传大小限制
  • 前台增加Video组件
  • 增加跳转界面VideoDetail

你可能感兴趣的:(学习)