项目介绍
这是一款基于SpringBoot+Vue的前后端分离的项目,麻雀虽小,五脏俱全,值得拥有!
全部源码放到文章最后
页面展示:
- 用户主页
- 管理员后台界面
技术选型
后端
- SpringBoot
- Hutool工具类库(*超好用)
- Redis缓存 (缓解多次刷新数据库压力)
- Lombok(减少写get、set等方法)
- Mysql5.7+
- Mybatis 、Mybatis-Plus
前端
- Vue2
- Vue-Router
- VueX
- ElementUI
- Apache ECharts (可视化图标插件)
- Axios
- 高德地图Api
数据库设计
Mysql5.7+ 、Nvaicat(MySQL可视化工具)
字符集
utf8mb4
排序规则
utf8mb4_unicode_ci
SpringBoot
目录结构
配置类
改成自己配置即可
server: ip: localhostport: 9090spring: datasource: driver-class-name: com.mysql.jdbc.Driverurl: jdbc:mysql://localhost:3306/boot?serverTimezone=GMT%2b8&useUnicode=true&characterEncoding=utf-8&useSSL=falseusername: rootpassword: redis: host: localhostport: 6379password: servlet: multipart: max-file-size: 100MBmax-request-size: 100MBmybatis: mapper-locations: classpath:mapper/*.xml #扫描所有mybatis的xml文件# configuration:# log-impl: org.apache.ibatis.logging.stdout.StdOutImplmybatis-plus:configuration:log-impl: org.apache.ibatis.logging.stdout.StdOutImplfiles:upload:path: /usr/xmp/files/
坐标导入
<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.2.1</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><scope>runtime</scope><version>5.1.47</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><!--mybatis-plus--><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.1</version></dependency><!--代码生成器--><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-generator</artifactId><version>3.5.1</version></dependency><dependency><groupId>org.apache.velocity</groupId><artifactId>velocity</artifactId><version>1.7</version></dependency><!--swagger--><dependency><groupId>io.springfox</groupId><artifactId>springfox-boot-starter</artifactId><version>3.0.0</version></dependency><!--hutool--><dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.7.20</version></dependency><dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml</artifactId><version>4.1.2</version></dependency><!--JWT--><dependency><groupId>com.auth0</groupId><artifactId>java-jwt</artifactId><version>3.10.3</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-cache</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies>
Jwt、Token验证
packagesqgxy.xmp.springboot.config.interceptor; importcn.hutool.core.util.StrUtil; importcom.auth0.jwt.JWT; importcom.auth0.jwt.JWTVerifier; importcom.auth0.jwt.algorithms.Algorithm; importcom.auth0.jwt.exceptions.JWTDecodeException; importcom.auth0.jwt.exceptions.JWTVerificationException; importsqgxy.xmp.springboot.common.Constants; importsqgxy.xmp.springboot.config.AuthAccess; importsqgxy.xmp.springboot.entity.User; importsqgxy.xmp.springboot.exception.ServiceException; importsqgxy.xmp.springboot.service.IUserService; importorg.springframework.beans.factory.annotation.Autowired; importorg.springframework.web.method.HandlerMethod; importorg.springframework.web.servlet.HandlerInterceptor; importjavax.servlet.http.HttpServletRequest; importjavax.servlet.http.HttpServletResponse; /*** @author xmp* @date 2022/5/9* @description JwtInterceptor* jwt拦截器*/publicclassJwtInterceptorimplementsHandlerInterceptor { privateIUserServiceuserService; publicbooleanpreHandle(HttpServletRequestrequest, HttpServletResponseresponse, Objecthandler) { Stringtoken=request.getHeader("token"); // 如果不是映射到方法直接通过if(!(handlerinstanceofHandlerMethod)){ returntrue; } else { HandlerMethodh= (HandlerMethod) handler; AuthAccessauthAccess=h.getMethodAnnotation(AuthAccess.class); if (authAccess!=null) { returntrue; } } // 执行认证if (StrUtil.isBlank(token)) { thrownewServiceException(Constants.CODE_401, "无token,请重新登录"); } // 获取 token 中的 user idStringuserId; try { userId=JWT.decode(token).getAudience().get(0); } catch (JWTDecodeExceptionj) { thrownewServiceException(Constants.CODE_401, "token验证失败,请重新登录"); } // 根据token中的userid查询数据库Useruser=userService.getById(userId); if (user==null) { thrownewServiceException(Constants.CODE_401, "用户不存在,请重新登录"); } // 用户密码加签验证 tokenJWTVerifierjwtVerifier=JWT.require(Algorithm.HMAC256(user.getPassword())).build(); try { jwtVerifier.verify(token); // 验证token } catch (JWTVerificationExceptione) { thrownewServiceException(Constants.CODE_401, "token验证失败,请重新登录"); } returntrue; } }
自定义注解
package sqgxy.xmp.springboot.config;
import java.lang.annotation.*;
/**
* @author xmp
* date 2022/5/13
* @description 自定义注解
*/
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface AuthAccess {
}
跨域问题
packagesqgxy.xmp.springboot.config; importorg.springframework.context.annotation.Bean; importorg.springframework.context.annotation.Configuration; importorg.springframework.web.cors.CorsConfiguration; importorg.springframework.web.cors.UrlBasedCorsConfigurationSource; importorg.springframework.web.filter.CorsFilter; /*** @author xmp* @date 2022/5/9* @description 跨域问题*/publicclassCorsConfig { // 当前跨域请求最大有效时长。这里默认1天privatestaticfinallongMAX_AGE=24*60*60; publicCorsFiltercorsFilter() { UrlBasedCorsConfigurationSourcesource=newUrlBasedCorsConfigurationSource(); CorsConfigurationcorsConfiguration=newCorsConfiguration(); corsConfiguration.addAllowedOrigin("*"); // 1 设置访问源地址corsConfiguration.addAllowedHeader("*"); // 2 设置访问源请求头corsConfiguration.addAllowedMethod("*"); // 3 设置访问源请求方法corsConfiguration.setMaxAge(MAX_AGE); source.registerCorsConfiguration("/**", corsConfiguration); // 4 对接口配置跨域设置returnnewCorsFilter(source); } }
接口统一返回包装类
packagesqgxy.xmp.springboot.common; importlombok.AllArgsConstructor; importlombok.Data; importlombok.NoArgsConstructor; /*** @author xmp* @date 2022/5/10* 接口统一返回包装类*/publicclassResult { privateStringcode; privateStringmsg; privateObjectdata; publicstaticResultsuccess() { returnnewResult(Constants.CODE_200, "", null); } publicstaticResultsuccess(Objectdata) { returnnewResult(Constants.CODE_200, "", data); } publicstaticResulterror(Stringcode, Stringmsg) { returnnewResult(code, msg, null); } publicstaticResulterror() { returnnewResult(Constants.CODE_500, "系统错误", null); } } 自定义Codepackagesqgxy.xmp.springboot.common; importlombok.AllArgsConstructor; importlombok.Data; importlombok.NoArgsConstructor; /*** @author xmp* @date 2022/5/10* 接口统一返回包装类*/publicclassResult { privateStringcode; privateStringmsg; privateObjectdata; publicstaticResultsuccess() { returnnewResult(Constants.CODE_200, "", null); } publicstaticResultsuccess(Objectdata) { returnnewResult(Constants.CODE_200, "", data); } publicstaticResulterror(Stringcode, Stringmsg) { returnnewResult(code, msg, null); } publicstaticResulterror() { returnnewResult(Constants.CODE_500, "系统错误", null); } }
Mybatis-Plus分页插件
packagesqgxy.xmp.springboot.config; importcom.baomidou.mybatisplus.annotation.DbType; importcom.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; importcom.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; importorg.mybatis.spring.annotation.MapperScan; importorg.springframework.context.annotation.Bean; importorg.springframework.context.annotation.Configuration; /*** @author xmp* @date 2022/5/9* @description MybatisPlusConfig mybatis-plus配置*/"sqgxy.xmp.springboot.mapper") (publicclassMybatisPlusConfig { // 最新版publicMybatisPlusInterceptormybatisPlusInterceptor() { MybatisPlusInterceptorinterceptor=newMybatisPlusInterceptor(); interceptor.addInnerInterceptor(newPaginationInnerInterceptor(DbType.MYSQL)); returninterceptor; } }
开发模式
以User为例
Entity
Entity实体层与数据库属性一一对应,lombok注解简化封装方法
packagesqgxy.xmp.springboot.entity; importcom.baomidou.mybatisplus.annotation.IdType; importcom.baomidou.mybatisplus.annotation.TableField; importcom.baomidou.mybatisplus.annotation.TableId; importcom.baomidou.mybatisplus.annotation.TableName; importjava.io.Serializable; importjava.util.Date; importjava.util.List; importio.swagger.annotations.ApiModel; importio.swagger.annotations.ApiModelProperty; importlombok.Getter; importlombok.Setter; importlombok.ToString; "sys_user") (value="User对象", description="") (publicclassUserimplementsSerializable { privatestaticfinallongserialVersionUID=1L; "id") (value="id", type=IdType.AUTO) (privateIntegerid; "用户名") (privateStringusername; "密码") (privateStringpassword; "昵称") (privateStringnickname; "邮箱") (privateStringemail; "电话") (privateStringphone; "地址") (privateStringaddress; "创建时间") (privateDatecreateTime; "头像") (privateStringavatarUrl; "角色") (privateStringrole; exist=false) (privateList<Course>courses; exist=false) (privateList<Course>stuCourses; }
mapper
mapper层对数据库进行数据持久化操作
packagesqgxy.xmp.springboot.mapper; importcom.baomidou.mybatisplus.extension.plugins.pagination.Page; importsqgxy.xmp.springboot.controller.dto.UserPasswordDTO; importsqgxy.xmp.springboot.entity.User; importcom.baomidou.mybatisplus.core.mapper.BaseMapper; importorg.apache.ibatis.annotations.Param; importorg.apache.ibatis.annotations.Update; /*** @author xmp* @date 2022/5/12*/publicinterfaceUserMapperextendsBaseMapper<User> { "update sys_user set password = #{newPassword} where username = #{username} and password = #{password}") (intupdatePassword(UserPasswordDTOuserPasswordDTO); Page<User>findPage(Page<User>page, ("username") Stringusername, ("email") Stringemail, ("address") Stringaddress); } UserMapper.xml<?xmlversion="1.0"encoding="UTF-8"?><!DOCTYPEmapperPUBLIC"-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mappernamespace="sqgxy.xmp.springboot.mapper.UserMapper"><resultMapid="pageUser"type="sqgxy.xmp.springboot.entity.User"><resultcolumn="id"property="id"/><resultcolumn="username"property="username"/><resultcolumn="nickname"property="nickname"/><resultcolumn="email"property="email"/><resultcolumn="phone"property="phone"/><resultcolumn="address"property="address"/><resultcolumn="create_time"property="createTime"/><resultcolumn="avatar_url"property="avatarUrl"/><resultcolumn="role"property="role"/><collectionproperty="courses"javaType="java.util.ArrayList"ofType="sqgxy.xmp.springboot.entity.Course"><resultcolumn="teacherCourseName"property="name"/><resultcolumn="teacherScore"property="score"/></collection><collectionproperty="stuCourses"javaType="java.util.ArrayList"ofType="sqgxy.xmp.springboot.entity.Course"><resultcolumn="stuCourseName"property="name"/><resultcolumn="stuScore"property="score"/></collection></resultMap><selectid="findPage"resultMap="pageUser">selectsys_user.*, sc.nameasstuCourseName, tc.nameasteacherCourseName, tc.scoreasteacherScore, sc.scoreasstuScorefromsys_userleftjoinstudent_courseonsys_user.id=student_course.student_idleftjoincoursesconstudent_course.course_id=sc.idleftjoincoursetconsys_user.id=tc.teacher_id<where><iftest="username != null and username != ''">andsys_user.usernamelikeconcat('%', #{username} ,'%') </if><iftest="email != null and email != ''">andsys_user.emaillikeconcat('%', #{email} ,'%') </if><iftest="address != null and address != ''">andsys_user.addresslikeconcat('%', #{address} ,'%') </if></where></select></mapper>
service层
即为业务逻辑层,可以理解为对一个或者多个dao进行得再次封装,主要是针对具体的问题的操作,把一些数据层的操作进行组合,间接与数据库打交道(提供操作数据库的方法)。要做这一层的话,要先设计接口,再实现类
packagesqgxy.xmp.springboot.service; importcom.baomidou.mybatisplus.extension.plugins.pagination.Page; importsqgxy.xmp.springboot.controller.dto.UserDTO; importsqgxy.xmp.springboot.controller.dto.UserPasswordDTO; importsqgxy.xmp.springboot.entity.User; importcom.baomidou.mybatisplus.extension.service.IService; /*** @author xmp* @date 2022/5/12*/publicinterfaceIUserServiceextendsIService<User> { UserDTOlogin(UserDTOuserDTO); Userregister(UserDTOuserDTO); voidupdatePassword(UserPasswordDTOuserPasswordDTO); Page<User>findPage(Page<User>objectPage, Stringusername, Stringemail, Stringaddress); }
packagesqgxy.xmp.springboot.service.impl; importcn.hutool.core.bean.BeanUtil; importcn.hutool.log.Log; importcom.baomidou.mybatisplus.core.conditions.query.QueryWrapper; importcom.baomidou.mybatisplus.extension.plugins.pagination.Page; importsqgxy.xmp.springboot.common.Constants; importsqgxy.xmp.springboot.common.RoleEnum; importsqgxy.xmp.springboot.controller.dto.UserDTO; importsqgxy.xmp.springboot.controller.dto.UserPasswordDTO; importsqgxy.xmp.springboot.entity.Menu; importsqgxy.xmp.springboot.entity.User; importsqgxy.xmp.springboot.exception.ServiceException; importsqgxy.xmp.springboot.mapper.RoleMapper; importsqgxy.xmp.springboot.mapper.RoleMenuMapper; importsqgxy.xmp.springboot.mapper.UserMapper; importsqgxy.xmp.springboot.service.IMenuService; importsqgxy.xmp.springboot.service.IUserService; importcom.baomidou.mybatisplus.extension.service.impl.ServiceImpl; importsqgxy.xmp.springboot.utils.TokenUtils; importorg.springframework.stereotype.Service; importjavax.annotation.Resource; importjava.util.ArrayList; importjava.util.List; /*** @author xmp* @date 2022/5/12*/publicclassUserServiceImplextendsServiceImpl<UserMapper, User>implementsIUserService { privatestaticfinalLogLOG=Log.get(); privateUserMapperuserMapper; privateRoleMapperroleMapper; privateRoleMenuMapperroleMenuMapper; privateIMenuServicemenuService; publicUserDTOlogin(UserDTOuserDTO) { Userone=getUserInfo(userDTO); if (one!=null) { BeanUtil.copyProperties(one, userDTO, true); // 设置tokenStringtoken=TokenUtils.genToken(one.getId().toString(), one.getPassword()); userDTO.setToken(token); Stringrole=one.getRole(); // ROLE_ADMIN// 设置用户的菜单列表List<Menu>roleMenus=getRoleMenus(role); userDTO.setMenus(roleMenus); returnuserDTO; } else { thrownewServiceException(Constants.CODE_600, "用户名或密码错误"); } } publicUserregister(UserDTOuserDTO) { Userone=getUserInfo(userDTO); if (one==null) { one=newUser(); BeanUtil.copyProperties(userDTO, one, true); // 默认一个普通用户的角色one.setRole(RoleEnum.ROLE_ADMIN.toString()); save(one); // 把 copy完之后的用户对象存储到数据库 } else { thrownewServiceException(Constants.CODE_600, "用户已存在"); } returnone; } publicvoidupdatePassword(UserPasswordDTOuserPasswordDTO) { intupdate=userMapper.updatePassword(userPasswordDTO); if (update<1) { thrownewServiceException(Constants.CODE_600, "密码错误"); } } publicPage<User>findPage(Page<User>page, Stringusername, Stringemail, Stringaddress) { returnuserMapper.findPage(page, username, email, address); } privateUsergetUserInfo(UserDTOuserDTO) { QueryWrapper<User>queryWrapper=newQueryWrapper<>(); queryWrapper.eq("username", userDTO.getUsername()); queryWrapper.eq("password", userDTO.getPassword()); Userone; try { one=getOne(queryWrapper); // 从数据库查询用户信息 } catch (Exceptione) { LOG.error(e); thrownewServiceException(Constants.CODE_500, "系统错误"); } returnone; } /*** 获取当前角色的菜单列表* @param roleFlag* @return*/privateList<Menu>getRoleMenus(StringroleFlag) { IntegerroleId=roleMapper.selectByFlag(roleFlag); // 当前角色的所有菜单id集合List<Integer>menuIds=roleMenuMapper.selectByRoleId(roleId); // 查出系统所有的菜单(树形)List<Menu>menus=menuService.findMenus(""); // new一个最后筛选完成之后的listList<Menu>roleMenus=newArrayList<>(); // 筛选当前用户角色的菜单for (Menumenu : menus) { if (menuIds.contains(menu.getId())) { roleMenus.add(menu); } List<Menu>children=menu.getChildren(); // removeIf() 移除 children 里面不在 menuIds集合中的 元素children.removeIf(child->!menuIds.contains(child.getId())); } returnroleMenus; } }
controller层
负责请求转发,接收页面过来的参数,传给service处理,接到返回值,并再次传给页面。
package sqgxy.xmp.springboot.controller;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.poi.excel.ExcelReader;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import sqgxy.xmp.springboot.common.Constants;
import sqgxy.xmp.springboot.common.Result;
import sqgxy.xmp.springboot.controller.dto.UserDTO;
import sqgxy.xmp.springboot.controller.dto.UserPasswordDTO;
import sqgxy.xmp.springboot.entity.User;
import sqgxy.xmp.springboot.service.IUserService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.net.URLEncoder;
import java.util.List;
/**
* @author xmp
* @since 2022-01-26
*/
@RestController
@RequestMapping("/user")
public class UserController {
@Value("${files.upload.path}")
private String filesUploadPath;
@Resource
private IUserService userService;
@PostMapping("/login")
public Result login(@RequestBody UserDTO userDTO) {
String username = userDTO.getUsername();
String password = userDTO.getPassword();
if (StrUtil.isBlank(username) || StrUtil.isBlank(password)) {
return Result.error(Constants.CODE_400, "参数错误");
}
UserDTO dto = userService.login(userDTO);
return Result.success(dto);
}
@PostMapping("/register")
public Result register(@RequestBody UserDTO userDTO) {
String username = userDTO.getUsername();
String password = userDTO.getPassword();
if (StrUtil.isBlank(username) || StrUtil.isBlank(password)) {
return Result.error(Constants.CODE_400, "参数错误");
}
return Result.success(userService.register(userDTO));
}
// 新增或者更新
@PostMapping
public Result save(@RequestBody User user) {
if (user.getId() == null && user.getPassword() == null) { // 新增用户默认密码
user.setPassword("123");
}
return Result.success(userService.saveOrUpdate(user));
}
/**
* 修改密码
* @param userPasswordDTO
* @return
*/
@PostMapping("/password")
public Result password(@RequestBody UserPasswordDTO userPasswordDTO) {
userService.updatePassword(userPasswordDTO);
return Result.success();
}
@DeleteMapping("/{id}")
public Result delete(@PathVariable Integer id) {
return Result.success(userService.removeById(id));
}
@PostMapping("/del/batch")
public Result deleteBatch(@RequestBody List<Integer> ids) {
return Result.success(userService.removeByIds(ids));
}
@GetMapping
public Result findAll() {
return Result.success(userService.list());
}
@GetMapping("/role/{role}")
public Result findUsersByRole(@PathVariable String role) {
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("role", role);
List<User> list = userService.list(queryWrapper);
return Result.success(list);
}
@GetMapping("/{id}")
public Result findOne(@PathVariable Integer id) {
return Result.success(userService.getById(id));
}
@GetMapping("/username/{username}")
public Result findByUsername(@PathVariable String username) {
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("username", username);
return Result.success(userService.getOne(queryWrapper));
}
@GetMapping("/page")
public Result findPage(@RequestParam Integer pageNum,
@RequestParam Integer pageSize,
@RequestParam(defaultValue = "") String username,
@RequestParam(defaultValue = "") String email,
@RequestParam(defaultValue = "") String address)
{
return Result.success(userService.findPage(new Page<>(pageNum, pageSize), username, email, address));
}
/**
* 导出接口
*/
@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 Result imp(MultipartFile file) throws Exception {
InputStream inputStream = file.getInputStream();
ExcelReader reader = ExcelUtil.getReader(inputStream);
// 方式1:(推荐) 通过 javabean的方式读取Excel内的对象,但是要求表头必须是英文,跟javabean的属性要对应起来
// List<User> 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 Result.success(true);
}
}
Vue
目录结构
跨域问题
安装axios:
npmiaxios-S
解决跨域问题,前端8080端口,请求数据后端9090端口
importaxiosfrom'axios'importrouterfrom"@/router"; import {serverIp} from"../../public/config"; constrequest=axios.create({ baseURL: `http://${serverIp}:9090`,timeout: 30000}) // request 拦截器// 可以自请求发送前对请求做一些处理// 比如统一加token,对请求参数统一加密request.interceptors.request.use(config=> { config.headers['Content-Type'] ='application/json;charset=utf-8'; letuser=localStorage.getItem("user") ?JSON.parse(localStorage.getItem("user")) : nullif (user) { config.headers['token'] =user.token; // 设置请求头 } returnconfig}, error=> { returnPromise.reject(error) }); // response 拦截器// 可以在接口响应后统一处理结果request.interceptors.response.use( response=> { letres=response.data; // 如果是返回的文件if (response.config.responseType==='blob') { returnres } // 兼容服务端返回的字符串数据if (typeofres==='string') { res=res?JSON.parse(res) : res } // 当权限验证不通过的时候给出提示if (res.code==='401') { // ElementUI.Message({// message: res.msg,// type: 'error'// });router.push("/login") } returnres; }, error=> { console.log('err'+error) // for debugreturnPromise.reject(error) } ) exportdefaultrequest
页面开发
看文档、B站讲解
Element-Ui
官网地址:https://element.eleme.io/#/zh-CN/component/installation
Apache ECharts
官网地址:https://echarts.apache.org/handbook/zh/get-started/
项目部署
环境:
centos7、jdk8、mysql、Redis、nginx
远程连接工具Xshell、Xftp
Vue打包
dist文件夹:
npmrunbuild
SpringBoot打包
按步骤
先清除,在编译,最后打包
上传之后
nginx
配置一下前端页面
location/ { root/public/app/dist; ===>自己的路径indexindex.htmlindex.htmlindex.htm; }
Boot
后台启动命令
nohupjava-jarxxx&
学习渠道
鱼皮的编程导航https://www.code-nav.cn/
B站的黑马程序员https://space.bilibili.com/37974444?spm_id_from=333.788.b_765f7570696e666f.2
B站的程序员青戈https://space.bilibili.com/402779077?spm_id_from=333.788.b_765f7570696e666f.2