一、课程技术
1、前端基于vue-admin-template开发,学会使用vue的动态菜单、动态路由、按钮权限的开发;
2、后端基于springboot、spring security开发,学会spring security在前后端分离项目中的开发;
3、课程从0开始手把手搭建项目,vue-admin-template动态菜单、动态路由、按钮权限判断;spring boot、spring security、token在前后端分离项目中的使用;
二、代码演示
package com.itmk.utils;
import com.itmk.status.StatusCode;
/**
* 数据返回工具类
*/
public class ResultUtils {
/**
* 无参数返回
* @return
*/
public static ResultVo succcess() {
return Vo(null, StatusCode.SUCCESS_CODE, null);
}
public static ResultVo success(String msg){
return Vo(msg,StatusCode.SUCCESS_CODE,null);
}
/**
* 返回带参数
* @param msg
* @param data
* @return
*/
public static ResultVo success(String msg,Object data){
return Vo(msg,StatusCode.SUCCESS_CODE,data);
}
public static ResultVo success(String msg,int code,Object data){
return Vo(msg,code,data);
}
public static ResultVo Vo(String msg, int code, Object data) {
return new ResultVo(msg, code, data);
}
/**
* 错误返回
* @return
*/
public static ResultVo error(){
return Vo(null,StatusCode.ERROR_CODE,null);
}
public static ResultVo error(String msg){
return Vo(msg,StatusCode.ERROR_CODE,null);
}
public static ResultVo error(String msg,int code,Object data){
return Vo(msg,code,data);
}
public static ResultVo error(String msg,int code){
return Vo(msg,code,null);
}
public static ResultVo error(String msg,Object data){
return Vo(msg, StatusCode.ERROR_CODE,data);
}
}
###### 1、新建员工实体
```js
package com.itmk.web.user.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
/**
* 员工表
*/
@Data
@TableName("sys_user")
public class User implements Serializable {
//设置主键自增
@TableId(type= IdType.AUTO)
private Long userId;
//登录名
private String loginName;
//登录密码
private String password;
//姓名
private String userName;
//电话
private String phone;
//性别 0:女 1:男
private String sex;
//身份证
private String idCard;
//是否是管理员 0:不是 1:是
private String isAdmin;
//0:在职 1:离职
private String status;
//0:启用 1:禁用
private String isUsed;
}
```
###### 2、新建员工mapper层
在web模块下新建com.itmk.web.user.mapper包,然后新建 UserMapper接口
```js
UserMapper接口需要继承 BaseMapper,继承BaseMapper的好处是我们可以直接使用Mybatis -Plus提供的通用CRUD方法
```
```js
package com.itmk.web.user.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.itmk.web.user.entity.User;
/**
* 员工数据访问层
*/
public interface UserMapper extends BaseMapper<User> {
}
```
###### 3、新建员工mapper层映射文件
在web模块的resources资源文件夹下新建mapper文件目录,然后新建UserMapper.xml,如下所示
```js
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.itmk.web.user.mapper.UserMapper">
</mapper>
```
###### 4、新建员工service层
4.1.在itmk-base-web模块新建com.itmk.web.user.service包,然后新建UserService接口,并继承IService接口
```js
package com.itmk.web.user.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.itmk.web.user.entity.User;
public interface UserService extends IService<User> {
//查询用户列表
IPage<User> list(UserParm parm);
}
```
4.2在itmk-base-web模块新建com.itmk.web.user.service.impl包,然后新建UserServiceImpl类
```js
package com.itmk.web.user.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.itmk.web.user.entity.User;
import com.itmk.web.user.mapper.UserMapper;
import com.itmk.web.user.service.UserService;
import org.springframework.stereotype.Service;
/**
* 继承 ServiceImpl 的好处是 可以使用 Mybatis-Plus的通用CRUD方法,
* implements UserService的原因,是如果 Mybatis-Plus的通用CRUD方法不够用,或者不符合开发需求的
* 时候,需要扩展我们自己定义的方法
* @Service 表示把该类交给spring 进行管理,我们就可以在其他类里面直接注入使用
*/
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
@Override
public IPage<User> list(UserParm parm) {
//构建分页对象
IPage<User> page = new Page<>();
page.setSize(parm.getPageSize());
page.setCurrent(parm.getCurrentPage());
//构造前端查询条件
QueryWrapper<User> query = new QueryWrapper<>();
if(StringUtils.isNotEmpty(parm.getPhone())){
query.lambda().like(User::getPhone,parm.getPhone());
}
if(StringUtils.isNotEmpty(parm.getUserName())){
query.lambda().like(User::getUserName,parm.getUserName());
}
return this.page(page,query);
}
}
```
###### 5、新建员工controller控制器
在itmk-base-web模块新建com.itmk.web.user.controller包,然后新建 UserController控制器
```js
package com.itmk.web.user.controller;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.itmk.utils.ResultUtils;
import com.itmk.utils.ResultVo;
import com.itmk.web.user.entity.User;
import com.itmk.web.user.entity.UserParm;
import com.itmk.web.user.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
/**
* 员工管理控制器
*/
@RestController
@RequestMapping("/api/user")
public class UserController {
@Autowired
private UserService userService;
/**
* 新增用户
* @param user
* @return
*/
@PostMapping
public ResultVo addUser(@RequestBody User user){
boolean save = userService.save(user);
if(save){
return ResultUtils.success("新增用户成功");
}
return ResultUtils.error("新增用户失败");
}
/**
* 编辑用户
* @param user
* @return
*/
@PutMapping
public ResultVo editUser(@RequestBody User user){
boolean b = userService.updateById(user);
if(b){
return ResultUtils.success("编辑用户成功");
}
return ResultUtils.error("编辑用户失败");
}
/**
* 删除用户
* @param userId
* @return
*/
@DeleteMapping
public ResultVo deleteUser(@RequestParam("userId") Long userId){
boolean b = userService.removeById(userId);
if(b){
return ResultUtils.success("删除用户成功");
}
return ResultUtils.error("删除用户失败");
}
/**
* 获取用户列表
* @param parm
* @return
*/
@GetMapping("/list")
public ResultVo list(UserParm parm){
IPage<User> list = userService.list(parm);
return ResultUtils.success("查询成功",list);
}
}
```
```js
package com.itmk.web.user.entity;
import lombok.Data;
@Data
public class UserParm {
//页容量
private Long pageSize;
//当前页
private Long curentPage;
//姓名
private String userName;
//电话
private String phone;
}
```
###### 6、新建启动类
在itmk-base-web模块的com.itmk包下新建 WyglApplication启动类
```js
package com.itmk;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class WyglApplication {
public static void main(String[] args) {
SpringApplication.run(WyglApplication.class,args);
}
}
```
#### 第8讲 员工管理列表制作
element ui官网
```js
https://element.eleme.cn/#/zh-CN/component/installation
```
###### 1、页面完整代码
```js
<template>
<el-main>
<!-- 搜索框 -->
<el-form
:model="parms"
ref="searchform"
label-width="80px"
:inline="true"
size="small"
>
<el-form-item label="姓名">
<el-input v-model="parms.userName"></el-input>
</el-form-item>
<el-form-item label="电话">
<el-input v-model="parms.phone"></el-input>
</el-form-item>
<el-form-item>
<el-button icon="el-icon-search">查询</el-button>
<el-button type="primary" icon="el-icon-plus">新增</el-button>
</el-form-item>
</el-form>
<!-- 员工表格 -->
<el-table :height="tableHeight" :data="tableList" empty-text="暂无数据" border stripe>
<el-table-column prop="userName" label="姓名"></el-table-column>
<el-table-column prop="phone" label="电话"></el-table-column>
<el-table-column prop="idCard" label="身份证"></el-table-column>
<el-table-column prop="sex" label="性别"></el-table-column>
<el-table-column prop="status" label="是否在职"></el-table-column>
<el-table-column prop="isUsed" label="账户状态"></el-table-column>
</el-table>
<el-pagination
@size-change="sizeChange"
@current-change="currentChange"
:current-page.sync="parms.curentPage"
:page-sizes="[10, 20, 40, 80, 100]"
:page-size="parms.pageSize"
:total="parms.total"
background
>
</el-pagination>
</el-main>
</template>
<script>
import { getUserListApi } from "@/api/user";
export default {
//所有需要在页面上展示的数据,都需要显示的在data里面进行定义
data() {
return {
//表格的高度
tableHeight: 0,
//搜索框数据绑定
parms: {
phone: "",
userName: "",
pageSize: 10,
curentPage: 1,
total: 0,
},
//表格数据
tableList: [],
};
},
created() {
this.getUserList();
},
mounted() {
this.$nextTick(() => {
this.tableHeight = window.innerHeight - 210;
});
},
methods: {
async getUserList() {
let res = await getUserListApi(this.parms);
if (res.code == 200) {
this.tableList = res.data.records;
}
console.log(res);
},
//页容量改变的时候触发
sizeChange(val) {
console.log(val);
},
//页数改变的时候触发
currentChange(val) {
console.log(val);
},
},
};
</script>
<style lang="scss" scoped>
</style>
```
###### 2、新建http.js
```js
import axios from 'axios'
import { MessageBox, Message } from 'element-ui'
import store from '@/store'
import { getToken } from '@/utils/auth'
import qs from 'qs'
// create an axios instance
//创建一个axios实例
const service = axios.create({
baseURL: process.env.VUE_APP_BASE_API_PRO, // url = base url + request url
// withCredentials: true, // send cookies when cross-domain requests
timeout: 5000 // request timeout
})
// request interceptor
//请求发送之前的拦截器
service.interceptors.request.use(
config => {
// do something before request is sent
//如果token存在,把token添加到请求的头部
if (store.getters.token) {
// let each request carry token
// ['X-Token'] is a custom headers key
// please modify it according to the actual situation
config.headers['X-Token'] = getToken()
}
return config
},
error => {
// do something with request error
console.log(error) // for debug
return Promise.reject(error)
}
)
// response interceptor
//请求返回之后的处理
service.interceptors.response.use(
/**
* If you want to get http information such as headers or status
* Please return response => response
*/
/**
* Determine the request status by custom code
* Here is just an example
* You can also judge the status by HTTP Status Code
*/
response => {
const res = response.data
// if the custom code is not 20000, it is judged as an error.
if (res.code !== 200) {
Message({
message: res.msg || '服务器出错',
type: 'error',
duration: 5 * 1000
})
// 50008: Illegal token; 50012: Other clients logged in; 50014: Token expired;
if (res.code === 50008 || res.code === 50012 || res.code === 50014) {
// to re-login
MessageBox.confirm('You have been logged out, you can cancel to stay on this page, or log in again', 'Confirm logout', {
confirmButtonText: 'Re-Login',
cancelButtonText: 'Cancel',
type: 'warning'
}).then(() => {
store.dispatch('user/resetToken').then(() => {
location.reload()
})
})
}
return Promise.reject(new Error(res.msg || '服务器出错'))
} else {
return res
}
},
error => {
console.log('err' + error) // for debug
Message({
message: error.msg || '服务器出错!',
type: 'error',
duration: 5 * 1000
})
return Promise.reject(error)
}
)
//请求方法
const http = {
post(url, params) {
return service.post(url, params, {
transformRequest: [(params) => {
return JSON.stringify(params)
}],
headers: {
'Content-Type': 'application/json'
}
})
},
put(url, params) {
return service.put(url, params, {
transformRequest: [(params) => {
return JSON.stringify(params)
}],
headers: {
'Content-Type': 'application/json'
}
})
},
//parm => {id:10}
// http://localhost:8089/api/user?id=10
get(url, params) {
return service.get(url, {
params: params,
paramsSerializer: (params) => {
return qs.stringify(params)
}
})
},
//parm => {id:10}
// http://localhost:8089/api/user/10
getRestApi(url, params) {
let _params
if (Object.is(params, undefined || null)) {
_params = ''
} else {
_params = '/'
for (const key in params) {
console.log(key)
console.log(params[key])
// eslint-disable-next-line no-prototype-builtins
if (params.hasOwnProperty(key) && params[key] !== null && params[key] !== '') {
_params += `${params[key]}/`
}
}
//去掉参数最后一位?
_params = _params.substr(0, _params.length - 1)
}
console.log(_params)
if (_params) {
return service.get(`${url}${_params}`)
} else {
return service.get(url)
}
},
//parm => {id:10}
// http://localhost:8089/api/user/10
delete(url, params) {
let _params
if (Object.is(params, undefined || null)) {
_params = ''
} else {
_params = '/'
for (const key in params) {
// eslint-disable-next-line no-prototype-builtins
if (params.hasOwnProperty(key) && params[key] !== null && params[key] !== '') {
_params += `${params[key]}/`
}
}
//去掉参数最后一位?
_params = _params.substr(0, _params.length - 1)
}
if (_params) {
return service.delete(`${url}${_params}`).catch(err => {
// message.error(err.msg)
return Promise.reject(err)
})
} else {
return service.delete(url).catch(err => {
// message.error(err.msg)
return Promise.reject(err)
})
}
},
upload(url, params) {
return service.post(url, params, {
headers: {
'Content-Type': 'multipart/form-data'
}
})
}
}
export default http
```
###### 3、修改src/api下的user.js
添加获取用户列表的方法
```js
import request from '@/utils/request'
import http from '@/utils/http'
//获取用户列表
export async function getUserListApi(parm){
return await http.get("/api/user/list",parm)
}
export function login(data) {
return request({
url: '/vue-admin-template/user/login',
method: 'post',
data
})
}
export function getInfo(token) {
return request({
url: '/vue-admin-template/user/info',
method: 'get',
params: { token }
})
}
export function logout() {
return request({
url: '/vue-admin-template/user/logout',
method: 'post'
})
}
```
###### 4、添加获取接口的地址
.env.development
```js
# just a flag
ENV = 'development'
# base api
VUE_APP_BASE_API = '/dev-api'
VUE_APP_BASE_API_PRO = 'http://localhost:8089/'
```
.env.production
```js
# just a flag
ENV = 'production'
# base api
VUE_APP_BASE_API = '/prod-api'
VUE_APP_BASE_API_PRO = 'http://localhost:8089/'
```
###### 5、后端跨域配置
```js
Access to XMLHttpRequest at 'http://localhost:8089/api/user/list?phone=&userName=&pageSize=10&curentPage=1' from origin 'http://localhost:9528' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
```
跨域配置
在itmk-base-web模块新建com.itmk.config.web包,然后新建WebMvcConfig配置类
```js
package com.itmk.config.web;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
/**
* 跨域配置
* @param registry
*/
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOriginPatterns("*")
.allowedMethods("*")
.allowedHeaders("*")
.maxAge(3600)
.allowCredentials(true);
}
}
```
###### 6、分页组件英文改中文
找到main.js文件
```js
//英文
import locale from 'element-ui/lib/locale/lang/en' // lang i18n
```
改为