Because the article is too long, it is divided into two parts
First half: juejin.cn/post/692204…
User management function
Above we have to write a simple login function, through the function, basic can end separation before and after the SpringBoot + Vue development has had a preliminary understanding, in practical work, the general work is project based on the basic framework has been forming, login, authentication, dynamic routing, request to encapsulate these basic functions may have been forming. Therefore, the daily work of the back-end is to write interface and business, and the daily work of the front-end is to adjust interface and write interface. Through the following user management function, we can be familiar with these daily development.
1. Back-end development
Backend development, CRUD is done.
1.1. Custom paging query
According to official documents, to carry out MP paging.
1.1.1. Paging Configuration
First, you need to configure paging, creating a paging configuration class
/ * * *@AuthorThree points *@Date 2021/1/23
* @DescriptionMP paging Settings */
@Configuration
@MapperScan("cn.fighter3.mapper.*.mapper*")
public class MybatisPlusConfig {
@Bean
public PaginationInterceptor paginationInterceptor(a) {
PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
// Set the request page to be larger than the maximum page operation, true to return to the home page, false to continue the request default false
// paginationInterceptor.setOverflow(false);
// Set the maximum number of pages per page, default 500, -1 is not limited
// paginationInterceptor.setLimit(500);
// Enable count join optimization for only part of the left join
paginationInterceptor.setCountSqlParser(new JsqlParserCountOptimize(true));
returnpaginationInterceptor; }}Copy the code
1.1.2. Customize SQL
As an enhancement tool of Mybatis, MP naturally supports custom SQL. In FACT, in MP, single table operations basically do not need to write SQL. This is just to demonstrate MP’s custom SQL, after all, in practical applications, batch operations, multi-table operations or more suitable for custom SQL implementation.
- Modify pom.xml by adding in
:
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml
true
src/main/resources
Copy the code
- Configuration file: Add the Mapper scan path and entity class name package to application.properties
# mybatis-plus
mybatis-plus.mapper-locations=classpath:cn/fighter3/mapper/*.xml
mybatis-plus.type-aliases-package=cn.fighter3.entity
Copy the code
- Define methods for paging queries in Usermapper.java
IPage<User> selectUserPage(Page<User> page,String keyword);
Copy the code
- Create the usermapper. XML file in the usermapper. Java directory
<? xml version="1.0" encoding="UTF-8"? > <! DOCTYPE mapper PUBLIC"- / / mybatis.org//DTD Mapper / 3.0 / EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.fighter3.mapper.UserMapper">
<select id="selectUserPage" resultType="User">
select * from user
<where>
<if test="keyword ! =null and keyword ! = "">
or login_name like CONCAT(The '%',#{keyword},The '%')
or user_name like CONCAT(The '%',#{keyword},The '%')
or email like CONCAT(The '%',#{keyword},The '%')
or address like CONCAT(The '%',#{keyword},The '%')
</if>
</where>
</select>
</mapper>
Copy the code
This query is also simpler, querying users by keyword.
OK, we are done with our custom paging query and can write a unit test to test it.
1.2. Control layer
Create a new UserControler, there is nothing in it, add, delete, change and check interface:
/ * * *@AuthorThree points *@Date 2021/1/23
* @DescriptionUser management */
@RestController
public class UserController {
@Autowired
private UserService userService;
/** ** *@param queryDTO
* @return* /
@PostMapping("/api/user/list")
public Result userList(@RequestBody QueryDTO queryDTO){
return new Result(200."",userService.selectUserPage(queryDTO));
}
/** * add *@param user
* @return* /
@PostMapping("/api/user/add")
public Result addUser(@RequestBody User user){
return new Result(200."",userService.addUser(user));
}
/** * update *@param user
* @return* /
@PostMapping("/api/user/update")
public Result updateUser(@RequestBody User user){
return new Result(200."",userService.updateUser(user));
}
/** * delete *@param id
* @return* /
@PostMapping("/api/user/delete")
public Result deleteUser(Integer id){
return new Result(200."",userService.deleteUser(id));
}
/** * Delete * in batches@param ids
* @return* /
@PostMapping("/api/user/delete/batch")
public Result batchDeleteUser(@RequestBody List<Integer> ids){
userService.batchDelete(ids);
return new Result(200."".""); }}Copy the code
It is also simpler to write here, calling the methods of the service layer directly.
1.3. Service Layer
The interface is not posted here, but the implementation class is as follows:
/ * * *@AuthorThree points *@Date 2021/1/23
* @Description* /
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
/** ** **/
@Override
public IPage<User> selectUserPage(QueryDTO queryDTO) {
Page<User> page=new Page<>(queryDTO.getPageNo(),queryDTO.getPageSize());
return userMapper.selectUserPage(page,queryDTO.getKeyword());
}
@Override
public Integer addUser(User user) {
return userMapper.insert(user);
}
@Override
public Integer updateUser(User user) {
return userMapper.updateById(user);
}
@Override
public Integer deleteUser(Integer id) {
return userMapper.deleteById(id);
}
@Override
public void batchDelete(List<Integer> ids) { userMapper.deleteBatchIds(ids); }}Copy the code
Here, too, there is little business logic.
In fact, the business layer does at least some validation work – I’ve seen some systems that only validate parameters on the client side. In fact, server-side validation is required (and would be rebuffed if not done 😔) because client-side validation is unreliable compared to server-side validation.
In paging query public IPage
selectUserPage(QueryDTO QueryDTO) using a business object, this writing method, can also be used with some parameters of the plug-in verification.
1.4. Business entities
Create a business entity class QueryDTO and define some parameters. This class is mainly used to transfer data from the front end to the back end. You can use some parameter verification plug-ins to add parameter verification rules.
/ * * *@AuthorThree points *@Date 2021/1/23
* @DescriptionQuery business entity * only three parameters are defined here. In practice, multiple parameters can be defined */
public class QueryDTO {
private Integer pageNo; / / page
private Integer pageSize; // Page size
private String keyword; / / key
// omit the getter and setter
}
Copy the code
A quick test, back end 👌
2. Front-end development
2.1, the home page
Earlier, after logging in, I jumped to HelloWorld, which was pretty crude. I wanted to jump directly to the user management view, but I didn’t think it was very nice, so I wrote a home page instead. Of course, this part is not the focus.
Have seen some background management system know, background management system is probably like the following layout:
The layout component Container is provided in ElementUI:
We all know that the root component is app. vue, of course, it is not appropriate to write the overall layout in app. vue, because there is a login page, so create a new home.vue under views, use the Container layout Container for layout, and use the NavMenu navigation menu to create the sidebar.
Of course, it is better not to write anything in home.vue and to pull out the top and sidebar as child pages (components).
<template>
<el-container class="home-container">
<! - the top -- -- >
<el-header style="margin-right: 15px; width: 100%">
<span class="nav-logo">😀</span>
<span class="head-title">Just A Demo</span>
<el-avatar
icon="el-icon-user-solid"
style="color: #222; float: right; padding: 20px"
>{{ this.$store.state.user.userName }}</el-avatar
>
</el-header>
<! - main body - - >
<el-container>
<! -- Sidebar -->
<el-aside width="13%">
<el-menu
:default-active="$route.path"
router
text-color="black"
active-text-color="red"
>
<el-menu-item
v-for="(item, i) in navList"
:key="i"
:index="item.name"
>
<i :class="item.icon"></i>
{{ item.title }}
</el-menu-item>
</el-menu>
</el-aside>
<el-main>
<! -- Route placeholder -->
<router-view></router-view>
</el-main>
</el-container>
</el-container>
</template>
<script>
export default {
name: "Home".data() {
return {
navList: [{name: "/index".title: "Home page".icon: "el-icon-s-home" },
{ name: "/user".title: "User Management".icon:"el-icon-s-custom"},]}; }};</script>
<style >
.nav-logo {
position: absolute;
padding-top: -1%;
left: 5%;
font-size: 40px;
}
.head-title {
position: absolute;
padding-top: 20px;
left: 15%;
font-size: 20px;
font-weight: bold;
}
</style>
Copy the code
uses the route placeholder
{
path: '/'.name: 'Default'.redirect: '/home'.component: Home
},
{
path: '/home'.name: 'Home'.component: Home,
meta: {
requireAuth: true
},
redirect: '/index'.children:[
{
path:'/index'.name:'Index'.component:() = > import('@/views/home/index'),
meta: {requireAuth:true}},}]},Copy the code
The home page originally did not want to put what things, later think, or put some people love to see – no other meaning, fast New Year, you brother-in-law New Year good. 🏮 😀
Image from Bingbing Weibo, see watermark.
2.2 User List
Create a directory named user under views, create a directory named index.vue under user, and add it as a child route to home:
{
path: '/home'.name: 'Home'.component: Home,
meta: {
requireAuth: true
},
redirect: '/index'.children:[
{
path:'/index'.name:'Index'.component:() = > import('@/views/home/index'),
meta: {requireAuth:true}}, {path:'/user'.name:'User'.component:() = >import('@/views/user/index'),
meta: {requireAuth:true}}},Copy the code
Next, write the user list function.
- First, encapsulate the API by adding an API to user.js that calls the paging query interface
// Get the user list
export function userList(data) {
return request({
url: '/user/list'.method: 'post',
data
})
}
Copy the code
- in
user/index.vue
Import the userList
import { userList} from "@/api/user";
Copy the code
- To load the user list when the interface is initialized, the lifecycle hook is used to call the interface to get the user list, and the code boils down
export default {
data() {
return {
userList: [].// List of users
total: 0.// Total number of users
// Gets the parameter object of the user list
queryInfo: {
keyword: "".// Query parameters
pageNo: 1.// Current page number
pageSize: 5.// Display the number of entries per page}},created() { // Lifecycle functions
this.getUserList()
},
methods: {
getUserList() {
userList(this.queryInfo)
.then((res) = > {
if (res.data.code === 200) {
// List of users
this.userList = res.data.data.records;
this.total = res.data.data.total;
} else {
this.$message.error(res.data.message);
}
})
.catch((err) = > {
console.log(err); }); }},Copy the code
-
We use a table component to bind the retrieved data
<! - form - ><el-table :data="userList" border stripe > <el-table-column type="index" label="Serial number"></el-table-column> <el-table-column prop="userName" label="Name"></el-table-column> <el-table-column prop="loginName" label="Login name"></el-table-column> <el-table-column prop="sex" label="Gender"></el-table-column> <el-table-column prop="email" label="Email"></el-table-column> <el-table-column prop="address" label="Address"></el-table-column> <el-table-column label="Operation"> </el-table-column> </el-table> Copy the code
Click User Management:
2.3, paging
In the figure above, we see a page bar at the bottom. Let’s look at the implementation of the page bar.
We use the Pagination component here:
<! -- Paging area --><el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="queryInfo.pageNo"
:page-sizes="[1, 2, 5, 10]"
:page-size="queryInfo.pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="total"
>
</el-pagination>
Copy the code
Two listening events:
// Listen for events where pageSize changes
handleSizeChange(newSize) {
// console.log(newSize)
this.queryInfo.pageSize = newSize;
// Re-initiate the list of requesting users
this.getUserList();
},
// Listen for the current page value change event
handleCurrentChange(newPage) {
// console.log(newPage)
this.queryInfo.pageNo = newPage;
// Re-initiate the list of requesting users
this.getUserList();
},
Copy the code
2.4. Retrieve users
The search box is already tied to queryInfo.keyword, just add button clicks and empty events to the top search area — retrieve the list of users:
<! -- Search area --><el-input
placeholder="Please enter the content"
v-model="queryInfo.keyword"
clearable
@clear="getUserList"
>
<el-button
slot="append"
icon="el-icon-search"
@click="getUserList"
></el-button>
</el-input>
Copy the code
The effect is as follows:
2.5. Add a user
- I’m going to write the API first, and I’m going to skip the import
// Add a user
export function userAdd(data) {
return request({
url: '/user/add'.method: 'post',
data
})
}
Copy the code
- To add a user we use two components: the Dialog Dialog component and the Form component.
<! Add user dialog box --><el-dialog
title="Add user"
:visible.sync="addDialogVisible"
width="30%"
@close="addDialogClosed"
>
<! Content body area -->
<el-form :model="userForm" label-width="70px">
<el-form-item label="Login name" prop="loginName">
<el-input v-model="userForm.loginName"></el-input>
</el-form-item>
<el-form-item label="Username" prop="userName">
<el-input v-model="userForm.userName"></el-input>
</el-form-item>
<el-form-item label="Password" prop="password">
<el-input v-model="userForm.password" show-password></el-input>
</el-form-item>
<el-form-item label="Gender" prop="sex">
<el-radio v-model="userForm.sex" label="Male">male</el-radio>
<el-radio v-model="userForm.sex" label="Female">female</el-radio>
</el-form-item>
<el-form-item label="Email" prop="email">
<el-input v-model="userForm.email"></el-input>
</el-form-item>
<el-form-item label="Address" prop="address">
<el-input v-model="userForm.address"></el-input>
</el-form-item>
</el-form>
<! -- Bottom button area -->
<span slot="footer" class="dialog-footer">
<el-button @click="addDialogVisible = false">Take away</el-button>
<el-button type="primary" @click="addUser">determine</el-button>
</span>
</el-dialog>
Copy the code
- use
addDialogVisible
Control dialog box visibility, usinguserForm
Bind modify user form:
addDialogVisible: false.// Controls whether the add user dialog box is displayed
userForm: {
/ / user
loginName: "".userName: "".password: "".sex: "".email: "".address: "",},Copy the code
- Two functions,
addUser
Add a user,addDialogClosed
Clear the form when the dialog closes
// Add a user
addUser() {
userAdd(this.userForm)
.then((res) = > {
if (res.data.code === 200) {
this.addDialogVisible = false;
this.getUserList();
this.$message({
message: "User added successfully".type: "success"}); }else {
this.$message.error("Failed to add user");
}
})
.catch((err) = > {
this.$message.error("Failed to add user");
console.log(err);
});
},
// Listen for the close event of the Add user dialog box
addDialogClosed() {
// The form content is reset to empty
this.$refs.addFormRef.resetFields();
},
Copy the code
Effect:
On the last page you can see the user we added:
2.6. Modify a user
- Write API
// Modify the user
export function userUpdate(data) {
return request({
url: '/user/update'.method: 'post',
data
})
}
Copy the code
- In the modify user case, we use a scope slot, through
slot-scope="scope"
Row receives the data for the current scope, then fetches the corresponding row of data through scope.row, and binds the specific property value.
<el-table-column label="Operation"> <! -- Scope slot --><template slot-scope="scope">
<! -- Modify button -->
<el-button
type="primary"
size="mini"
icon="el-icon-edit"
@click="showEditDialog(scope.row)"
></el-button>
</template>
</el-table-column>
Copy the code
- The specific modifications are still in the form of dialog boxes and forms
<! -- Modify user's dialog box --><el-dialog title="Modify user" :visible.sync="editDialogVisible" width="30%">
<! Content body area -->
<el-form :model="editForm" label-width="70px">
<el-form-item label="Username" prop="userName">
<el-input v-model="editForm.userName" :disabled="true"></el-input>
</el-form-item>
<el-form-item label="Email" prop="email">
<el-input v-model="editForm.email"></el-input>
</el-form-item>
<el-form-item label="Address" prop="address">
<el-input v-model="editForm.address"></el-input>
</el-form-item>
</el-form>
<! -- Bottom button area -->
<span slot="footer" class="dialog-footer">
<el-button @click="editDialogVisible = false">Take away</el-button>
<el-button type="primary" @click="editUser">determine</el-button>
</span>
</el-dialog>
Copy the code
editDialogVisible
Control dialog box displays,editForm
Binding modifies the user form
editDialogVisible: false.// Controls whether the dialog box for modifying user information is displayed
editForm: {
id: "".loginName: "".userName: "".password: "".sex: "".email: "".address: "",},Copy the code
showEditDialog
In addition to handling dialog box displays, modify user objects are bound.editUser
Modify a user.
// Listen to modify user status
showEditDialog(userinfo) {
this.editDialogVisible = true;
console.log(userinfo);
this.editForm = userinfo;
},
// Modify the user
editUser() {
userUpdate(this.editForm)
.then((res) = > {
if (res.data.code === 200) {
this.editDialogVisible = false;
this.getUserList();
this.$message({
message: "User modification succeeded".type: "success"}); }else {
this.$message.error("Failed to modify user");
}
})
.catch((err) = > {
this.$message.error("Modify user exception");
console.loge(err);
});
},
Copy the code
2.7. Delete a user
- api
// Delete the user
export function userDelete(id) {
return request({
url: '/user/delete'.method: 'post'.params: {
id
}
})
}
Copy the code
-
Add a delete button in the action bar’s scope slot to pass the scope’s ID property directly into it
<el-table-column label="Operation"> <! -- Scope slot --><template slot-scope="scope"> <! -- Modify button --> <el-button type="primary" size="mini" icon="el-icon-edit" @click="showEditDialog(scope.row)" ></el-button> <! Delete button --> <el-button type="danger" size="mini" icon="el-icon-delete" @click="removeUserById(scope.row.id)" ></el-button> </template> </el-table-column> Copy the code
-
RemoveUserById Deletes a user based on the user ID
// Delete the user information based on the ID
async removeUserById(id) {
// A dialog box is displayed asking the user whether to delete it
const confirmResult = await this.$confirm(
"This operation will permanently delete the user. Do you want to continue?"."Tip",
{
confirmButtonText: "Sure".cancelButtonText: "Cancel".type: "warning",
}
).catch((err) = > err);
// If the user confirms the deletion, the return value is the string confirm
// If the user cancels the deletion, the string cancel is returned
// console.log(confirmResult)
if (confirmResult == "confirm") {
// Delete the user
userDelete(id)
.then((res) = > {
if (res.data.code === 200) {
this.getUserList();
this.$message({
message: "User deleted successfully".type: "success"}); }else {
this.$message.error("Failed to delete user");
}
})
.catch((err) = > {
this.$message.error("User deletion exception");
console.loge(err); }); }},Copy the code
Effect:
2.8. Delete users in batches
- api
// Delete users in batches
export function userBatchDelete(data) {
return request({
url: '/user/delete/batch'.method: 'post',
data
})
}
Copy the code
- There is an optional way to manually add one in the ElementUI table component
el-table-column
Set,type
Properties forselection
Can be
<el-table-column type="selection" width="55"> </el-table-column>
Copy the code
Add event to table:
@selection-change="handleSelectionChange"
Copy the code
Here’s the official example:
export default {
data() {
return {
multipleSelection: []}},methods: {
handleSelectionChange(val) {
this.multipleSelection = val; }}}Copy the code
The multipleSelection structure fetched in this example looks like this. We only need the ID, so let’s do something about it:
export default {
data() {
return {
multipleSelection: [].ids: [].}},methods: {
handleSelectionChange(val) {
this.multipleSelection = val;
// Assign a value to the deleted IDS
this.multipleSelection.forEach((item) = > {
this.ids.push(item.id);
console.log(this.ids); }); }}}Copy the code
- Next is simple, batch delete operation directly CV above delete, change the API function and parameters can be
// Delete users in batches
async batchDeleteUser(){
// A dialog box is displayed asking the user whether to delete it
const confirmResult = await this.$confirm(
This operation will permanently delete the user. Do you want to continue?."Tip",
{
confirmButtonText: "Sure".cancelButtonText: "Cancel".type: "warning",
}
).catch((err) = > err);
// If the user confirms the deletion, the return value is the string confirm
// If the user cancels the deletion, the string cancel is returned
if (confirmResult == "confirm") {
// Delete users in batches
userBatchDelete(this.ids)
.then((res) = > {
if (res.data.code === 200) {
this.$message({
message: "Succeeded in deleting users in batches".type: "success"});this.getUserList();
} else {
this.$message.error("Failed to batch Delete users");
}
})
.catch((err) = > {
this.$message.error("Failed to delete users in batches");
console.log(err);
});
}
Copy the code
Effect:
The complete code is a little long, I will not paste, please check the source code.
Six, summarized
Through this example, WE believe that you have a preliminary grasp of SpringBoot+Vue front-end and back-end separation development.
Of course, since this example is not a complete project, it is technically and functionally sloppy 😓
Interested students can further expand and refine this example. 👏 👏 👏
Source code address:Gitee.com/fighter3/sp…
Reference:
[1] : Vue.js – progressive JavaScript framework
[2] : Element – Site rapid prototyping tool
[3] : how2j.cn
[4] : Vue + Spring Boot project actual combat
[5] : A look to understand! Front-end and back-end separated login interception based on Springboot interceptor
[6] : Hand touch hand, take you with vue wanlu backstage series a (basic chapter
[7] : E-commerce management system instance of Vue + ElementUI