Chapter 3 Reservation Management - Package Management
1.Picture Storage Scheme
[Goal]
Health Project, Picture Storage Scheme
[Path]
1: Introduction
(1) Introduction of file upload function
2: Qiniuyun Storage
(1) Registration
(2) New storage space
(3) View storage space information
(4) Developer Center
- File Upload
- File Delete
(5) Authentication
(6) Java SDK operation Qiniuyun
(7) Encapsulation tool class
[Explanation]
1.1.introduce
In practice, there are many servers that handle different functions. For example:
Application Server: Responsible for deploying our applications
Database Server: Run Our Database
File Server: The server responsible for storing files uploaded by users
The purpose of sub-server processing is to make the servers perform their duties, thereby improving the efficiency of our projects.
Common picture storage schemes:
Option 1: Build a picture server using nginx
Scenario 2: Use an open source distributed file storage system, such as Fastdfs==, HDFS, and so on
Option 3: Use cloud storage, such as Ali Cloud, Qiniuyun, etc.
1.2.Qiniuyun Storage
Qiniuyun (subordinate to Shanghai Qiniu Information Technology Co., Ltd.)Is the leading enterprise cloud computing service provider with visual intelligence and data intelligence as the core, and is also a well-known intelligent video cloud service provider in China. It provides services for more than 700,000 enterprises, covering 80% of the domestic netizens. CDN is introduced around rich media scenarios.Accelerate, Container Cloud, Big Data Platform, Deep Learning Platform and other products, and provide one-stop smart video cloud solutions. Provide sustainable smart video cloud ecology for all industries and applications, help enterprises to quickly cloud, and create broader business value.
Official website: https://www.qiniu.com/
Through the introduction of Qiniuyun official website, we can know that it provides a variety of services. We mainly use the object storage service provided by Qiniuyun to store pictures.
1.2.1.Registration, Login
To use Qiniuyun's services, you first need to register as a member.Address: https://portal.qiniu.com/signup
After successful login, click the Administration Console in the upper right corner of the page:
Note: Name authentication is required after successful login.
1.2.2.New Storage Space
To store pictures, we need to create a new storage space in the Qiniuyun Management Console. Click the Add Now button under the Object Storage on the first page of the Management Console, and the page jumps to the New Storage Space page:
You can create multiple storage spaces that are independent of each other.
1.2.3.View Storage Space Information
When a storage space is created, the name of the created storage space is displayed in the list menu of storage spaces on the left side. Click on the name to view information about the current storage space.
Focus on the information in Content Management.
1.2.4.Developer Center
You can learn how to operate the Qiniuyun service through the developer center provided by Qiniuyun, Address: https://developer.qiniu.com/
Click Object Storage to jump to the Object Storage Development page at: https://developer.qiniu.com/kodo
Operation steps:
Step 1: Import the jar package:
Step 2: Authentication
Click on the Administration Console, click on the top right Icon
You can test against uploaded and deleted files provided in the document:
Testing in health_common
1.2.4.1. File upload
public class TestQiniu { // Upload local files @Test public void uploadFile(){ //Construct a configuration class with the specified Zone object Configuration cfg = new Configuration(Zone.zone0()); //...other parameters reference class notes UploadManager uploadManager = new UploadManager(cfg); //...Generate upload credentials and prepare to upload String accessKey = "xxx"; String secretKey = "xxx-xxx"; String bucket = "xxx"; //In the case of Windows, the format is D:\\qiniu\test.png, which supports Chinese String localFilePath = "D:/2.jpg"; //Use hash value of file content as file name without specifying key by default String key = null; Auth auth = Auth.create(accessKey, secretKey); String upToken = auth.uploadToken(bucket); try { Response response = uploadManager.put(localFilePath, key, upToken); //Resolve upload success results DefaultPutRet putRet = new Gson().fromJson(response.bodyString(), DefaultPutRet.class); System.out.println(putRet.key); System.out.println(putRet.hash); } catch (QiniuException ex) { Response r = ex.response; System.err.println(r.toString()); try { System.err.println(r.bodyString()); } catch (QiniuException ex2) { //ignore } } } }
1.2.4.2. File deletion
// Delete files in space @Test public void deleteFile(){ //Construct a configuration class with the specified Zone object Configuration cfg = new Configuration(Zone.zone0()); //...other parameters reference class notes String accessKey = "xxx"; String secretKey = "xxxx-xxx"; String bucket = "xxxx"; String key = "xxxx"; Auth auth = Auth.create(accessKey, secretKey); BucketManager bucketManager = new BucketManager(auth, cfg); try { bucketManager.delete(bucket, key); } catch (QiniuException ex) { //If an exception is encountered, deletion fails System.err.println(ex.code()); System.err.println(ex.response.toString()); } }
Qiniuyun provides a variety of ways to operate object storage services. This project uses Java SDK mode with address: https://developer.qiniu.com/kodo/sdk/1239/java
Using the Java SDK to manipulate Qiniuyun requires the following maven coordinates to be imported: (the project has been introduced)
<dependency> <groupId>com.qiniu</groupId> <artifactId>qiniu-java-sdk</artifactId> <version>7.2.0</version> </dependency>
1.2.5.authentication
All functions of the Java SDK require legal authorization. Authorization certificate signing requires a pair of valid Access Key s and Secret Key s under the seven bull account, which can be used in the personal center of the seven bull cloud management console. https://portal.qiniu.com/user/key ) Obtained as follows:
1.2.6.Java SDK Operations Qiniuyun
In this chapter, we need to use the Java SDK provided by Qiniuyun to upload and delete pictures. We can refer to the example provided by the government.
Upload file:
//Constructs a configuration class with a specified Zone object, zone0 for East China (default) Configuration cfg = new Configuration(Zone.zone0()); //...other parameters reference class notes UploadManager uploadManager = new UploadManager(cfg); //...Generate upload credentials and prepare to upload String accessKey = "your access key"; String secretKey = "your secret key"; String bucket = "your bucket name"; //Use hash value of file content as file name without specifying key by default String key = null; try { byte[] uploadBytes = "hello qiniu cloud".getBytes("utf-8"); ByteArrayInputStream byteInputStream=new ByteArrayInputStream(uploadBytes); Auth auth = Auth.create(accessKey, secretKey); String upToken = auth.uploadToken(bucket); try { Response response = uploadManager.put(byteInputStream,key,upToken,null, null); //Resolve upload success results DefaultPutRet putRet = new Gson().fromJson(response.bodyString(), DefaultPutRet.class); System.out.println(putRet.key); System.out.println(putRet.hash); } catch (QiniuException ex) { Response r = ex.response; System.err.println(r.toString()); try { System.err.println(r.bodyString()); } catch (QiniuException ex2) { //ignore } } } catch (UnsupportedEncodingException ex) { //ignore }
Delete files:
//Constructs a configuration class with a specified Zone object, zone0 for East China (default) Configuration cfg = new Configuration(Zone.zone0()); //...other parameters reference class notes String accessKey = "your access key"; String secretKey = "your secret key"; String bucket = "your bucket name"; String key = "your file key"; Auth auth = Auth.create(accessKey, secretKey); BucketManager bucketManager = new BucketManager(auth, cfg); try { bucketManager.delete(bucket, key); } catch (QiniuException ex) { //If an exception is encountered, deletion fails System.err.println(ex.code()); System.err.println(ex.response.toString()); }
1.2.7.Encapsulation Tool Class
To facilitate the operation of Qiniuyun Storage Service, we can simply transform the case provided by the government into a tool class that can be used directly in our project:
package com.itheima.health.utils; import com.google.gson.Gson; import com.itheima.health.constant.MessageConstant; import com.qiniu.common.QiniuException; import com.qiniu.common.Zone; import com.qiniu.http.Response; import com.qiniu.storage.BucketManager; import com.qiniu.storage.Configuration; import com.qiniu.storage.UploadManager; import com.qiniu.storage.model.BatchStatus; import com.qiniu.storage.model.DefaultPutRet; import com.qiniu.util.Auth; import java.util.ArrayList; import java.util.List; public class QiNiuUtils { private static final String ACCESSKEY = "SFEru-42dYFEvmHot4dz1UhsepDmOPDql0AfFt8p"; private static final String SECRETKEY = "aCzett8JLbldF42PhQGzw6ymQyWreY4Fu8drPKG3"; private static final String BUCKET = "sz98"; public static final String DOMAIN= "http://qfhy5itom.hn-bkt.clouddn.com/"; public static void main(String[] args) { uploadFile("C:\\Users\\Eric\\Desktop\\file\\timg.jpg","dd2.jpg"); //removeFiles("20190529083159.jpg","20190529083241.jpg"); } /** * Bulk Delete * @param filenames List of filenames to delete * @return Delete Successful Filename List */ public static List<String> removeFiles(String... filenames){ // Delete Successful Filename List List<String> removeSuccessList = new ArrayList<String>(); if(filenames.length > 0){ // Create Warehouse Manager BucketManager bucketManager = getBucketManager(); // Create Batch Processor BucketManager.Batch batch = new BucketManager.Batch(); // Bulk Delete Multiple Files batch.delete(BUCKET,filenames); try { // Get the response from the server Response res = bucketManager.batch(batch); // Get batch status BatchStatus[] batchStatuses = res.jsonToObject(BatchStatus[].class); for (int i = 0; i < filenames.length; i++) { BatchStatus status = batchStatuses[i]; String key = filenames[i]; System.out.print(key + "\t"); if (status.code == 200) { removeSuccessList.add(key); System.out.println("delete success"); } else { System.out.println("delete failure"); } } } catch (QiniuException e) { e.printStackTrace(); throw new RuntimeException(MessageConstant.PIC_UPLOAD_FAIL); } } return removeSuccessList; } public static void uploadFile(String localFilePath, String savedFilename){ UploadManager uploadManager = getUploadManager(); String upToken = getToken(); try { Response response = uploadManager.put(localFilePath, savedFilename, upToken); //Resolve upload success results DefaultPutRet putRet = new Gson().fromJson(response.bodyString(), DefaultPutRet.class); System.out.println(String.format("key=%s, hash=%s",putRet.key, putRet.hash)); } catch (QiniuException ex) { Response r = ex.response; System.err.println(r.toString()); try { System.err.println(r.bodyString()); } catch (QiniuException ex2) { //ignore } throw new RuntimeException(MessageConstant.PIC_UPLOAD_FAIL); } } public static void uploadViaByte(byte[] bytes, String savedFilename){ UploadManager uploadManager = getUploadManager(); String upToken = getToken(); try { Response response = uploadManager.put(bytes, savedFilename, upToken); //Resolve upload success results DefaultPutRet putRet = new Gson().fromJson(response.bodyString(), DefaultPutRet.class); System.out.println(putRet.key); System.out.println(putRet.hash); } catch (QiniuException ex) { Response r = ex.response; System.err.println(r.toString()); try { System.err.println(r.bodyString()); } catch (QiniuException ex2) { //ignore } throw new RuntimeException(MessageConstant.PIC_UPLOAD_FAIL); } } private static String getToken(){ // Create Authorization Auth auth = Auth.create(ACCESSKEY, SECRETKEY); // Authenticated token String upToken = auth.uploadToken(BUCKET); return upToken; } private static UploadManager getUploadManager(){ //Construct a configuration class with the specified Zone object Configuration cfg = new Configuration(Zone.zone2()); //Build Upload Manager return new UploadManager(cfg); } private static BucketManager getBucketManager(){ // Create Authorization Information Auth auth = Auth.create(ACCESSKEY, SECRETKEY); // Create a manager that operates on a warehouse return new BucketManager(auth, new Configuration(Zone.zone2())); } }
Place this tool class in the health_common project and use it later.
[Summary]
1: Introduction
(1) The difference between traditional file storage and cloud storage, using cloud storage
2: Qiniuyun Storage
(1) Registration
(2) New storage space
(3) View storage space information
(4) Developer Center Certification
(5) Create key: Access Key, Sercret Key
(6) Java SDK operation QiNiuUitls
(7) Encapsulation tool class
QiNiuUitls saved in transcript
2.New Package
[Goal]
New Package
[Path]
-
Picture Upload
-
When the picture is selected, SetmealController receives the uploaded picture
-
Get the original picture name, truncate to the suffix name
-
Generate unique file names, stitch suffix names
-
Call Qiniu to upload file
-
Return data to page
- Picture name for future formData submissions
- Pictures on the page need to echo the full path QiNiuUtils.DOMAIN+Picture Name
{ flag: message: data:{ imgName: Picture Name, domain: QiNiuUtils.DOMAIN } }
-
-
-
After creating a new pop-up window, get all check groups bound to tableData to select Check groups related to the meal
CheckGroupController service dao. findAll
-
Submit
-
Determine the event, submit formData => Setmeal, checkgroupIds => Integer[], prompt the result, close the new window and refresh the list data if successful
-
SetmealController receives formData with Setmeal, Integer[] receives checkgroupIds, calls service add, and returns the results to the page
-
SetmealService
- Add Package
- Get the id of the meal
- The relationship between adding meals and the inspection team
-
SetmealDao
- Add Set SelectectKey t_setmeal
- Add Package to Check Group Relation t_setmeal_checkgroup
-
[Explanation]
2.1.requirement analysis
The meal is actually a collection of examination groups, such as an "Enrollment Check-up Package", which can include more than one examination group: general examination, blood routine, urine routine, liver function and so on.
So when you add a meal, you need to select the inspection group included in the meal.
The entity class corresponding to the meal is Setmeal.
public class Setmeal implements Serializable { private Integer id; private String name; private String code; private String helpCode; private String sex;//Suitability for meals: 0 for 1 male and 2 female private String age;//Suitable age for meals private Float price;//Package Price private String remark; private String attention; private String img;//Picture Name for Meal (Picture Name for Storing on the Cloud of Seven - Unique) private List<CheckGroup> checkGroups;//Check group corresponding to check-up plan, many-to-many relationship }
Where the img field represents the path where the meal corresponds to the picture storage (used to store the name of the picture on Qiniuyun)
t_setmeal table
t_setmeal_checkgroup table
2.2.Foreground code
The meal management page corresponds to the setmeal.html page. The basic structure of the page has been written according to the prototype of product design. Now it is necessary to improve the dynamic effect of the page.
2.2.1.Pop-up new window
A new window has been added to the page for the purpose of hiding it. Simply change the dialogFormVisible property that controls the display state to the true interface to show the new window. When you click the new button, the binding method is handleCreate, so modify the value of the dialogFormVisible property to true in the handleCreate method. At the same time, each point is required to increase the user experience.Empty the form input when you click the New button.
Since you also need to select the inspection group included in the new meal, the new meal window is divided into two parts: basic information and inspection group information, as shown below:
(1): New button binds click event, corresponding handleCreate
<el-button type="primary" class="butT" @click="handleCreate()">Newly build</el-button>
(2): handleCreate() method:
// Reset Form resetForm() { // Empty Form Content this.formData = {}; // Empty the selected inspection group this.checkgroupIds = []; // Default Show Meal Basic Information Label this.activeName = 'first'; // Clear Selected Pictures this.imageUrl = ''; this.formData.img = ''; }, // Pop-up Add Window handleCreate() { this.resetForm(); //Pop-up Add Window this.dialogFormVisible = true; },
2.2.2.Dynamic display of inspection group list
Although the pop-up of the new window has now been completed, all the checkgroup information list data needs to be dynamically displayed and checked in the checkgroup information tab. The steps are as follows:
(1) Define model data
tableData:[],//Add Check Group List Data in Form Window checkgroupIds:[],//Check group check box corresponding id in add form window
(2) Dynamic display of checklist data from tableData model data defined above
<el-tab-pane label="Check Group Information" name="second"> <div class="checkScrol"> <table class="datatable"> <thead> <tr> <th>Choice</th> <th>Item Code</th> <th>entry name</th> <th>Project Description</th> </tr> </thead> <tbody> <!--Loop traversal tableData--> <tr v-for="c in tableData"> <td> <!--Checkbox Binding checkgroupIds,Store in value is id--> <input :id="c.id" v-model="checkgroupIds" type="checkbox" :value="c.id"> </td> <td><label :for="c.id">{{c.code}}</label></td> <td><label :for="c.id">{{c.name}}</label></td> <td><label :for="c.id">{{c.remark}}</label></td> </tr> </tbody> </table> </div> </el-tab-pane>
Where v-model="checkgroupIds", used to echo check boxes.
(3) Improve the handleCreate method, send ajax requests to query all inspection group data and assign the results to tableData model data for page table display
// Pop-up Add Window handleCreate() { this.resetForm(); //Pop-up Add Window this.dialogFormVisible = true; // Load Check Group List Data axios.get('/checkgroup/findAll.do').then(res => { if(res.data.flag){ this.tableData = res.data.data; }else{ this.$message.error(res.data.message); } }) },
(4) Query all inspection group data by extending methods in CheckGroupController, CheckGroupService, CheckGroupServiceImpl, CheckGroupDao, CheckGroupDao.xml, respectively
1: CheckGroupController:
@GetMapping("/findAll") public Result findAll(){ List<CheckGroup> all = checkGroupService.findAll(); return new Result(true, MessageConstant.QUERY_CHECKGROUP_SUCCESS,all); }
2: CheckGroupService:
/** * Query all check groups * @return */ List<CheckGroup> findAll();
3: CheckGroupServiceImpl:
/** * Query all check groups * @return */ @Override public List<CheckGroup> findAll() { return checkGroupDao.findAll(); }
4: CheckGroupDao:
/** * Query all check groups * @return */ List<CheckGroup> findAll();
5: CheckGroupDao.xml:
<select id="findAll" resultType="checkgroup"> select * From t_checkgroup </select>
2.2.3.Picture upload and Preview
The element UI's upload component, el-upload, is used here to provide various upload effects that can be previewed after a successful upload.
Steps to achieve:
(1) Define model data for picture preview of subsequently uploaded files:
imageUrl:null,//Model data for picture preview after uploading pictures
(2) Define ElementUI upload components:
<el-form-item label="Upload pictures"> <!-- action: Submitted Pictures url, Stop sending pictures auto-upload: Whether to upload files automatically, and upload them as soon as you have selected them action Of url in name: Parameter name of uploaded file, MultipartFile imgFile show-file-list: Show the list of uploaded files, only one picture is needed here, do not show on-success: Callback method after successful upload before-upload: Method called before upload --> <el-upload class="avatar-uploader" action="/setmeal/upload.do" :auto-upload="autoUpload" name="imgFile" :show-file-list="false" :on-success="handleAvatarSuccess" :before-upload="beforeAvatarUpload"> <!-- Picture echo if imageUrl Value, output img Label Use when uploading pictures successfully imageUrl Assign full paths Background response back data format imageUrl=domain+imgName { flag: message: data: { imgName: Save picture name to database domain: The domain name of Qiniu } } --> <img v-if="imageUrl" :src="imageUrl" class="avatar"> <i v-else class="el-icon-plus avatar-uploader-icon"></i> </el-upload> </el-form-item>
(3) Define the corresponding hook function:
handleAvatarSuccess(response, file) { // Prompt for success or failure, to play back the picture this.$message({ message: response.message, type: response.flag?"success":"error" }) if(response.flag){ // Echo Picture this.imageUrl = response.data.domain + response.data.imgName; // There is no img parameter in the form, and the background database uses the IMG field to complement its value // json data in front end {key, value}=> map, // Object.Attribute name (nonexistent) => map.put (nonexistent key,value) this.formData.img = response.data.imgName; } }, //Execute before uploading pictures beforeAvatarUpload(file) { const isJPG = file.type === 'image/jpeg'; const isLt2M = file.size / 1024 / 1024 < 2; if (!isJPG) { this.$message.error('Upload plan pictures can only be JPG format!'); } if (!isLt2M) { this.$message.error('Upload plan picture size cannot exceed 2 MB!'); } return isJPG && isLt2M; },
(4) Create SetmealController to receive uploaded files
package com.itheima.health.controller; import com.alibaba.dubbo.config.annotation.Reference; import com.itheima.health.constant.MessageConstant; import com.itheima.health.entity.Result; import com.itheima.health.service.SetmealService; import com.itheima.health.utils.QiNiuUtils; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; import java.io.IOException; import java.util.HashMap; import java.util.Map; import java.util.UUID; /** * Description: No Description * User: Eric */ @RestController @RequestMapping("/setmeal") public class SetmealController { @Reference private SetmealService setmealService; /** * Meal Upload Picture * @param imgFile * @return */ @PostMapping("/upload") public Result upload(MultipartFile imgFile){ //-Get the original picture name, truncate to the suffix name String originalFilename = imgFile.getOriginalFilename(); String extension = originalFilename.substring(originalFilename.lastIndexOf(".")); //-Generate unique file names, stitch suffix names String filename = UUID.randomUUID() + extension; //-Call Seven bulls to upload files try { QiNiuUtils.uploadViaByte(imgFile.getBytes(), filename); //-Return data to page //{ // flag: // message: // data:{ // imgName: Picture name, // domain: QiNiuUtils.DOMAIN // } //} Map<String,String> map = new HashMap<String,String>(); map.put("imgName",filename); map.put("domain", QiNiuUtils.DOMAIN); return new Result(true, MessageConstant.PIC_UPLOAD_SUCCESS,map); } catch (IOException e) { e.printStackTrace(); } return new Result(false, MessageConstant.PIC_UPLOAD_FAIL); } }
Note: Don't forget to upload components in the spring profile
Configured in springmvc.xml
<!--File Upload Component--> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <property name="maxUploadSize" value="104857600" /><!--Maximum upload file size--> <property name="maxInMemorySize" value="4096" /> <property name="defaultEncoding" value="UTF-8"/> </bean>
2.2.4.Submit Request
When the user clicks the OK button in the new window, an ajax request is sent to submit the data to the background for database operation. The data submitted to the background is div id ed into two parts: basic information about the meal (corresponding model data is formData) and an array of check group IDs (corresponding model data is checkgroupIds).
(1) To determine the button binding click event, the corresponding handleAdd function
<div slot="footer" class="dialog-footer"> <el-button @click="dialogFormVisible = false">cancel</el-button> <el-button type="primary" @click="handleAdd()">Determine</el-button> </div>
(2) Perfect handleAdd method
//Add Submission handleAdd () { axios.post('/setmeal/add.do?checkgroupIds=' + this.checkgroupIds, this.formData).then(res=>{ this.$message({ message: res.data.message, type: res.data.flag?"success":"error" }) if(res.data.flag){ // Close Add Window this.dialogFormVisible = false; // Refresh List Data this.findPage(); } }) },
2.3.Background code
2.3.1. Controller
Adding methods in SetmealController
@PostMapping("/add") public Result add(@RequestBody Setmeal setmeal, Integer[] checkgroupIds){ // Call Business Service Add setmealService.add(setmeal, checkgroupIds); // Response results return new Result(true, MessageConstant.ADD_SETMEAL_SUCCESS); }
2.3.2.Service Interface
Create SetmealService interface and provide new methods
package com.itheima.health.service; import com.itheima.health.pojo.Setmeal; import java.util.List; /** * Description: No Description * User: Eric */ public interface SetmealService { /** * Add Package * @param setmeal * @param checkgroupIds */ void add(Setmeal setmeal, Integer[] checkgroupIds); }
2.3.3.Service Implementation Class
Create SetmealServiceImpl service implementation class and implement new methods
package com.itheima.health.service.impl; import com.alibaba.dubbo.config.annotation.Service; import com.itheima.health.dao.SetmealDao; import com.itheima.health.pojo.Setmeal; import com.itheima.health.service.SetmealService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; /** * Description: No Description * User: Eric */ @Service(interfaceClass = SetmealService.class) public class SetmealServiceImpl implements SetmealService { @Autowired private SetmealDao setmealDao; /** * Add Package * @param setmeal * @param checkgroupIds */ @Override @Transactional public void add(Setmeal setmeal, Integer[] checkgroupIds) { // Add Meal Information setmealDao.add(setmeal); // Get the id of the meal Integer setmealId = setmeal.getId(); // The relationship between adding meals and the inspection team if(null != checkgroupIds){ for (Integer checkgroupId : checkgroupIds) { setmealDao.addSetmealCheckGroup(setmealId, checkgroupId); } } } }
2.3.4.Dao interface
Create SetmealDao interface and provide related methods
package com.itheima.health.dao; import com.itheima.health.pojo.Setmeal; import org.apache.ibatis.annotations.Param; /** * Description: No Description * User: Eric */ public interface SetmealDao { /** * Add Package * @param setmeal */ void add(Setmeal setmeal); /** * The relationship between adding meals and the inspection team * @param setmealId * @param checkgroupId */ void addSetmealCheckGroup(@Param("setmealId") Integer setmealId, @Param("checkgroupId") Integer checkgroupId); }
2.3.5.Mapper Mapping File
Create SetmealDao.xml file and define related SQL statements
<?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="com.itheima.health.dao.SetmealDao"> <insert id="add" parameterType="setmeal"> <selectKey resultType="int" keyProperty="id" order="AFTER"> select last_insert_id() </selectKey> insert into t_setmeal (name,code,helpCode,sex,age,price,remark,attention,img) values(#{name},#{code},#{helpCode},#{sex},#{age},#{price},#{remark},#{attention},#{img}) </insert> <insert id="addSetmealCheckGroup" parameterType="int"> insert into t_setmeal_checkgroup (setmeal_id, checkgroup_id) values (#{setmealId},#{checkgroupId}) </insert> </mapper>
2.4.Perfect file upload, Redis stores picture names (ignore, follow-up)
We've already finished uploading the files and storing the pictures on the Qiniuyun server. But one problem with this process is that if users upload pictures without ultimately saving the package information to our database, then the pictures we upload become garbage pictures. For these garbage pictures, we need to clean up regularly to free up disk space.We need to be able to distinguish which are junk pictures and which are not. How can we do that?
The solution is to use redis to save the image name by:
1. After the user uploads the picture, save the picture name to a Set collection in redis, for example, the set name is setmealPicResources
2. When the user adds the meal, save the picture name to another Set collection in redis, such as setmealPicDbResources
3. Calculate the difference between the setmealPicResources collection and the setmealPicDbResources collection. The result is the name collection of garbage pictures. Clean up these pictures
In this section, we will complete the first two steps, and the third step (cleaning up pictures) will be achieved later through a timer task.
Steps to achieve:
(1) Provide the Spring configuration file spring-redis.xml in the health_web project
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!--Jedis Configuration of connection pools--> <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig"> <property name="maxTotal"> <value>200</value> </property> <property name="maxIdle"> <value>50</value> </property> <property name="testOnBorrow" value="true"/> <property name="testOnReturn" value="true"/> </bean> <bean id="jedisPool" class="redis.clients.jedis.JedisPool"> <constructor-arg name="poolConfig" ref="jedisPoolConfig" /> <constructor-arg name="host" value="127.0.0.1" /> <constructor-arg name="port" value="6379" type="int" /> <constructor-arg name="timeout" value="30000" type="int" /> </bean> </beans>
Also introduced using tags in springmvc.xml
<import resource="classpath:spring-redis.xml"></import>
(2) Provide Redis constant classes in the health_common project
package com.itheima.health.constant; public class RedisConstant { //Meal Picture All Picture Names public static final String SETMEAL_PIC_RESOURCES = "setmealPicResources"; //Picture name of the meal picture saved in the database public static final String SETMEAL_PIC_DB_RESOURCES = "setmealPicDbResources"; }
(3) Perfect SetmealController and save the picture name to redis collection after successful file upload
@Autowired private JedisPool jedisPool; //Picture Upload @RequestMapping("/upload") public Result upload(@RequestParam("imgFile")MultipartFile imgFile){ try{ //Get the original file name String originalFilename = imgFile.getOriginalFilename(); int lastIndexOf = originalFilename.lastIndexOf("."); //Get File Suffix String suffix = originalFilename.substring(lastIndexOf); //Use UUID to randomly generate file names to prevent overwriting files with the same name String fileName = UUID.randomUUID().toString() + suffix; QiniuUtils.upload2Qiniu(imgFile.getBytes(),fileName); //Picture uploaded successfully Result result = new Result(true, MessageConstant.PIC_UPLOAD_SUCCESS,fileName); //Save the uploaded picture name in Redis, Redis-based Set Collection Storage jedisPool.getResource().sadd(RedisConstant.SETMEAL_PIC_RESOURCES,fileName); return result; }catch (Exception e){ e.printStackTrace(); //Picture upload failed return new Result(false,MessageConstant.PIC_UPLOAD_FAIL); } }
Add to:
//Save the uploaded picture name in Redis, Redis-based Set Collection Storage jedisPool.getResource().sadd(RedisConstant.SETMEAL_PIC_RESOURCES,fileName);
(4) Perfect the SetmealController service class and store the picture name in the redis collection after saving the package information
@Autowired private JedisPool jedisPool; /** * Add to */ @PostMapping("/add") public Result add(@RequestBody Setmeal setmeal, Integer[] checkgroupIds){ // Invoke Service Update setmealService.add(setmeal, checkgroupIds); // Successfully added, to record useful pictures in the redis collection Jedis jedis = jedisPool.getResource(); jedis.sadd(RedisConstant.SETMEAL_PIC_DB_RESOURCES, setmeal.getImg()); jedis.close(); return new Result(true, MessageConstant.ADD_SETMEAL_SUCCESS); } @PostMapping("/update") public Result update(@RequestBody Setmeal setmeal, Integer[] checkgroupIds){ // Get the name of the original picture, determine if it has changed, and if so, remove the old picture from the useful collection Setmeal setmealInDb = setmealService.findById(setmeal.getId()); // Invoke Service Update setmealService.update(setmeal, checkgroupIds); Jedis jedis = jedisPool.getResource(); // Determine if deletion is necessary from a useful set if(!setmealInDb.getImg().equals(setmeal.getImg())){ //If the picture is modified, the old one will be useless, so delete it jedis.srem(RedisConstant.SETMEAL_PIC_DB_RESOURCES, setmealInDb.getImg()); } // Successfully modified to record useful pictures in the redis collection jedis.sadd(RedisConstant.SETMEAL_PIC_DB_RESOURCES, setmeal.getImg()); jedis.close(); return new Result(true, MessageConstant.EDIT_SETMEAL_SUCCESS); } // Delete Package * delete */ @PostMapping("/delete") public Result deleteById(int id){ // Check the picture name Setmeal setmeal = setmealService.findById(id); // Call Business Service Delete setmealService.deleteById(id); // Remove this deleted picture from the redis, which saves the collection of pictures stored in the database Jedis jedis = jedisPool.getResource(); jedis.srem(RedisConstant.SETMEAL_PIC_DB_RESOURCES, setmeal.getImg()); jedis.close(); return new Result(true, MessageConstant.DELETE_SETMEAL_SUCCESS); }
Test:
Delete the junk pictures, complete with the following code, create a test class under the health_web project, and delete it
@ContextConfiguration(locations = "classpath:spring-redis.xml") @RunWith(value = SpringJUnit4ClassRunner.class) public class TestDeletePic { @Autowired JedisPool jedisPool; // Delete different pictures stored in Redis with two different key values @Test public void test(){ Set<String> set = jedisPool.getResource().sdiff(RedisConstant.SETMEAL_PIC_RESOURCE, RedisConstant.SETMEAL_PIC_DB_RESOURCE); Iterator<String> iterator = set.iterator(); while (iterator.hasNext()){ String pic = iterator.next(); System.out.println("Deleted pictures:"+pic); // Delete pictures from Qiniuyun QiniuUtils.deleteFileFromQiniu(pic); // Delete data with key value SETMEAL_PIC_RESOURCE in Redis jedisPool.getResource().srem(RedisConstant.SETMEAL_PIC_RESOURCE,pic); } } }
The project manager said that the code has been completed so that you can execute the above code in the early morning. We won't really wait until the early morning to execute it. What should we do?
Jump to Chapter Four, Learning Task Scheduling Quartz
[Summary]
- Make the name of the picture uploaded to Qiniu unique
- When the upload component of the elementUI succeeds, the callback handleAvatarSuccess(response) is handled by the elementUI, response=>Result.
- Picture in the meal: To be displayed on the page (full path), the database only stores its name, the form pair will not be submitted, there is no img, complete the formData to complete the img.
4: Perfect file upload, Redis stores picture names (will say)
3.Check-up Meal Page
[Goal]
Check-up Meal List Paging
[Path]
1: Front Desk Code
(1) Define pagination, QueryPageBean for pagination-related model data
(2) Define the paging method findPage
(3) Perfect paging method execution timing load, query (1), page number change, add success, modify success, delete
2: Background code
Business:
- Paged List Display of Check-up Meal
findPage method:
- Submit the query condition pagination information, prompt the results, and bind the returned result set res.data.data.rows to the dataList, and the total number to the pagination.total
- SetmealController receives QueryPageBean, invokes the business service query page Result, wraps it up and returns it to the front end
- SetmealServiceImp uses PageHelper paging, has query conditions to achieve fuzzy query splicing, calls dao query, returns PageResult object
- SetmealDao findByCondition
[Explanation]
3.1.Foreground code
3.1.1.Define Paging Related Model Data
pagination: {//Paging related model data currentPage: 1,//CurrentPage pageSize:10,//Number of records displayed per page total:0,//Total Records queryString:null//query criteria }, dataList: [],//Page List Data to Display on Current Page
3.1.2.Define Paging Method
(1) The findPage method is provided in the page for paging queries. In order to display the paging data directly after the setmeal.html page is loaded, the findPage method can be called in the hook function created provided by VUE.
//Hook function, automatically executed after VUE object initialization is complete created() { this.findPage(); },
(2) findPage() method:
//Paging Query findPage() { axios.post('/setmeal/findPage.do', this.pagination).then(res => { if(res.data.flag){ // Bind Paging Result Set this.dataList = res.data.data.rows; // Total Records this.pagination.total = res.data.data.total; }else{ this.$message.error(res.data.message); } }) },
3.1.3.Improve Paging Method Execution Timing
In addition to calling the findPage method in the created hook function to query paging data, the findPage method is also called to reinitiate the query request when the user clicks the query button or the page number in the paging bar.
(1) Bind click events for query buttons, call findPage method
<el-button @click="handleCurrentChange(1)" class="dalfBut">query</el-button>
(2) Bind a current-change event for the page bar component, which is defined by the page bar component itself and triggered when the page number changes. The corresponding handleCurrentChange handles the event
<div class="pagination-container"> <el-pagination class="pagiantion" @current-change="handleCurrentChange" :current-page="pagination.currentPage" :page-size="pagination.pageSize" layout="total, prev, pager, next, jumper" :total="pagination.total"> </el-pagination> </div>
Define handleCurrentChange method
//Switch Page Numbers handleCurrentChange(currentPage) { //CurrtPage is the switched page number this.pagination.currentPage = currentPage; this.findPage(); }
3.2.Background code
3.2.1. Controller
Adding Paging Query Method in SetmealController
/** * Paging Query */ @PostMapping("/findPage") public Result findPage(@RequestBody QueryPageBean queryPageBean){ // Invoke Service Paging Query PageResult<Setmeal> pageResult = setmealService.findPage(queryPageBean); return new Result(true, MessageConstant.QUERY_SETMEAL_SUCCESS,pageResult); }
3.2.2.Service Interface
Extended Paging Query Method in SetmealService Service Interface
/** * Paging Query * @param queryPageBean * @return */ PageResult<Setmeal> findPage(QueryPageBean queryPageBean);
3.2.3.Service Implementation Class
Implement paging queries in the SetmealServiceImpl service implementation class and paging based on the Mybatis Paging Assistant plug-in
/** * Paging Query * @param queryPageBean * @return */ @Override public PageResult<Setmeal> findPage(QueryPageBean queryPageBean) { PageHelper.startPage(queryPageBean.getCurrentPage(), queryPageBean.getPageSize()); // query criteria if(!StringUtils.isEmpty(queryPageBean.getQueryString())){ // Fuzzy Query% queryPageBean.setQueryString("%" + queryPageBean.getQueryString() + "%"); } // Conditional query, this query statement will be paginated Page<Setmeal> page = setmealDao.findByCondition(queryPageBean.getQueryString()); return new PageResult<Setmeal>(page.getTotal(), page.getResult()); }
3.2.4.Dao interface
Extending Paging Query Method in SetmealDao Interface
/** * Conditional Query * @param queryString * @return */ Page<Setmeal> findByCondition(String queryString);
3.2.5.Mapper Mapping File
Add a SQL definition to the SetmealDao.xml file
<select id="findByCondition" parameterType="String" resultType="setmeal"> select * From t_setmeal <if test="value != null and value.length > 0"> where code like #{queryString} or name like #{queryString} or helpCode like #{queryString} </if> </select>
[Summary]
1: Front Desk Code
(1) Define paging-related model data
(2) Define paging methods
(3) Improve the timing of paging method execution
4.Edit Package
[Goal]
Edit Package
[Path]
(1) Bind Edit click events
(2) Pop-up edit window echo data, form initialization
-
Echo Meal Data, Picture Preview (setmeal.img=picture name) Set the full path of the picture {setmeal: setmeal, imageUrl: domain+setmeal.getImg()}
{ flag: message: data:{ setmeal: setmeal, domain: QiNiuUtils.DOMAIN } } this.formData = res.data.data.setmeal this.imageUrl = res.data.data.domain + this.formData.img
-
Query Check Group List
-
The ID of the check group that the current meal has for the check box to be checked
(3) Send requests, edit save packages
- Edit Save Package
- Delete Meal Check Group Intermediate Table Data and Re-add Meal Check Group Intermediate Table Data
[Explanation]
4.1.Front page
When users click the edit button, they need to pop up the edit window and echo the currently recorded data. When users finish modifying, they click the OK button to submit the modified data to the background for database operation. When data echo is done here, besides echoing the basic information of the package, they also need to echo the inspection group included in the current package.(echoes as a check box check).
4.1.1. Binding Click Events
(1) The click event needs to be bound to the Edit button and the current row data is passed as a parameter to the handler
<el-table-column label="operation" align="center"> <template slot-scope="scope"> <el-button type="primary" size="mini" @click="handleUpdate(scope.row)">edit</el-button> <el-button size="mini" type="danger" @click="handleDelete(scope.row)">delete</el-button> </template> </el-table-column>
(2) Add handleUpdate method to methods
// Pop-up editing window handleUpdate(row) { alert(row.id); },
4.1.2. Pop-up edit window echo data
Write an edit window for the current page, which can be modified by copying the new plan window, which needs to be hidden by default.
(1) Define the model in vue's data
dialogFormVisible4Edit:false//Control Edit Window Show/Hide
(2) Define edit window pages
Add an edit pop-up below the new window
<div class="edit-form"> <el-dialog title="Edit Package" :visible.sync="dialogFormVisible4Edit"> <template> <el-tabs v-model="activeName" type="card"> <el-tab-pane label="Essential information" name="first"> <el-form label-position="right" label-width="100px"> <el-row> <el-col :span="12"> <el-form-item label="Code"> <el-input v-model="formData.code"/> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="Name"> <el-input v-model="formData.name"/> </el-form-item> </el-col> </el-row> <el-row> <el-col :span="12"> <el-form-item label="Applicability gender"> <el-select v-model="formData.sex"> <el-option label="Unlimited" value="0"></el-option> <el-option label="male" value="1"></el-option> <el-option label="female" value="2"></el-option> </el-select> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="Mnemonic code"> <el-input v-model="formData.helpCode"/> </el-form-item> </el-col> </el-row> <el-row> <el-col :span="12"> <el-form-item label="Package Price"> <el-input v-model="formData.price"/> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="Available age"> <el-input v-model="formData.age"/> </el-form-item> </el-col> </el-row> <el-row> <el-col :span="24"> <el-form-item label="Upload pictures"> <el-upload class="avatar-uploader" action="/setmeal/upload.do" :auto-upload="autoUpload" name="imgFile" :show-file-list="false" :on-success="handleAvatarSuccess" :before-upload="beforeAvatarUpload"> <img v-if="imageUrl" :src="imageUrl" class="avatar"> <i v-else class="el-icon-plus avatar-uploader-icon"></i> </el-upload> </el-form-item> </el-col> </el-row> <el-row> <el-col :span="24"> <el-form-item label="Explain"> <el-input v-model="formData.remark" type="textarea"></el-input> </el-form-item> </el-col> </el-row> <el-row> <el-col :span="24"> <el-form-item label="Matters needing attention"> <el-input v-model="formData.attention" type="textarea"></el-input> </el-form-item> </el-col> </el-row> </el-form> </el-tab-pane> <el-tab-pane label="Check Group Information" name="second"> <div class="checkScrol"> <table class="datatable"> <thead> <tr> <th>Choice</th> <th>Item Code</th> <th>entry name</th> <th>Project Description</th> </tr> </thead> <tbody> <tr v-for="c in tableData"> <td> <input :id="c.id" v-model="checkgroupIds" type="checkbox" :value="c.id"> </td> <td><label :for="c.id">{{c.code}}</label></td> <td><label :for="c.id">{{c.name}}</label></td> <td><label :for="c.id">{{c.remark}}</label></td> </tr> </tbody> </table> </div> </el-tab-pane> </el-tabs> </template> <div slot="footer" class="dialog-footer"> <el-button @click="dialogFormVisible4Edit = false">cancel</el-button> <el-button type="primary" @click="handleEdit()">Determine</el-button> </div> </el-dialog> </div>
Add a method to determine events
// Edit Submission handleEdit(){ }
In the handleUpdate method, the edit window needs to be displayed, and multiple ajax requests need to be sent to query the current package data, all checklist data, and the checkgroup id contained in the current package for basic data echo
// Pop-up editing window handleUpdate(row){ this.resetForm(); this.dialogFormVisible4Edit = true; // id of the meal var id = row.id; axios.get("/setmeal/findById.do?id=" + id).then(res => { if(res.data.flag){ // Echo Meal Information // res.data.data => resultMap {setmeal, domain} this.formData = res.data.data.setmeal; // Echo Picture this.imageUrl = res.data.data.domain+this.formData.img; axios.get('/checkgroup/findAll.do').then(resp => { if(resp.data.flag){ this.tableData = resp.data.data; // Get the selected checkgroup id axios.get('/setmeal/findCheckgroupIdsBySetmealId.do?id=' + id).then(response => { if(response.data.flag){ this.checkgroupIds = response.data.data; }else{ this.$message.error(response.data.message); } }) }else{ this.$message.error(resp.data.message); } }) }else{ this.$message.error(res.data.message); } }) },
4.1.3. Send requests, edit save packages
(1) After the modification is completed in the edit window, click OK button to submit the request, so you need to bind event for OK button and provide handleEdit handler
<el-button type="primary" @click="handleEdit()">Determine</el-button>
(2) handleEdit() method
// Edit Submission handleEdit(){ //Submit inspection group information for this.formData, check item id this.checkgroupIds selected axios.post('/setmeal/update.do?checkgroupIds=' + this.checkgroupIds, this.formData).then(res => { this.$message({ message: res.data.message, type: res.data.flag?"success":"error" }) if(res.data.flag){ // Close the editing window this.dialogFormVisible4Edit = false; // Refresh List Data this.findPage(); } }) }
4.2.Background code
4.2.1. Controller
Adding methods in SetmealController
/** * Inquire about meal information via id */ @GetMapping("/findById") public Result findById(int id){ // Invoke Service Query Setmeal setmeal = setmealService.findById(id); // Full path is required for front end to display pictures // Encapsulate in map to solve picture path problem Map<String,Object> resultMap = new HashMap<String,Object>(); resultMap.put("setmeal", setmeal); // formData resultMap.put("domain", QiNiuUtils.DOMAIN); // domain return new Result(true, MessageConstant.QUERY_SETMEAL_SUCCESS,resultMap); } /** * Query selected checkgroup ids by id */ @GetMapping("/findCheckgroupIdsBySetmealId") public Result findCheckgroupIdsBySetmealId(int id){ List<Integer> checkgroupIds = setmealService.findCheckgroupIdsBySetmealId(id); return new Result(true, MessageConstant.QUERY_CHECKGROUP_SUCCESS,checkgroupIds); } /** * modify */ @PostMapping("/update") public Result update(@RequestBody Setmeal setmeal, Integer[] checkgroupIds){ // Invoke Business Service Modification setmealService.update(setmeal, checkgroupIds); // Response results return new Result(true, MessageConstant.EDIT_SETMEAL_SUCCESS); }
4.2.2.Service Interface
Extension method in SetmealService service interface
/** * Query by id * @param id * @return */ Setmeal findById(int id); /** * Query selected checkgroup ids by id * @param id * @return */ List<Integer> findCheckgroupIdsBySetmealId(int id); /** * Modify Package * @param setmeal * @param checkgroupIds */ void update(Setmeal setmeal, Integer[] checkgroupIds);
4.2.3.Service Implementation Class
Implement editing methods in the SetmealServiceImpl implementation class
@Override public Setmeal findById(int id) { return setmealDao.findById(id); } /** * Query selected checkgroup ids by id * @param id * @return */ @Override public List<Integer> findCheckgroupIdsBySetmealId(int id) { return setmealDao.findCheckgroupIdsBySetmealId(id); } /** * Modify Package * @param setmeal * @param checkgroupIds */ @Override @Transactional public void update(Setmeal setmeal, Integer[] checkgroupIds) { // Update plan information first setmealDao.update(setmeal); // Delete old relationships setmealDao.deleteSetmealCheckGroup(setmeal.getId()); // Add a new relationship if(null != checkgroupIds){ for (Integer checkgroupId : checkgroupIds) { setmealDao.addSetmealCheckGroup(setmeal.getId(), checkgroupId); } } }
4.2.4.Dao interface
Extension methods in the SetmealDao interface
/** * Query by id * @param id * @return */ Setmeal findById(int id); /** * Query selected checkgroup ids by id * @param id * @return */ List<Integer> findCheckgroupIdsBySetmealId(int id); /** * Update Meal Information * @param setmeal */ void update(Setmeal setmeal); /** * Delete old relationships * @param id */ void deleteSetmealCheckGroup(Integer id);
4.2.5.Mapper Mapping File
Extending SQL statements in SetmealDao.xml
<select id="findById" parameterType="int" resultType="setmeal"> select * From t_setmeal where id=#{id} </select> <select id="findCheckgroupIdsBySetmealId" parameterType="int" resultType="int"> select checkgroup_id from t_setmeal_checkgroup where setmeal_id=#{id} </select> <update id="update" parameterType="setmeal"> update t_setmeal set name=#{name}, code=#{code}, helpCode=#{helpCode}, sex=#{sex}, age=#{age}, price=#{price}, remark=#{remark}, attention=#{attention}, img=#{img} where id=#{id} </update> <delete id="deleteSetmealCheckGroup" parameterType="int"> delete from t_setmeal_checkgroup where setmeal_id=#{id} </delete>
[Summary]
- Add Binding Edit Click Event
- Copy the new window, change to edit window, add dialogFormVisable4Edit to define the display of the edit window
(2) Pop-up edit window to echo data, copy added windows: determine button-bound events, edit window display control variable dialogFormVisiable4Edit (window definition, data definition), add handleUpdate method (methods) to methods, add handleEdit method (methods)
-
Echo Meal Data
-
Query Check Group List
-
Check boxes for check groups currently available in the meal need to be checked
(3) Send requests, edit save packages
- Edit Package Updates
- Delete Meal Check Group Intermediate Table Data and Re-add Meal Check Group Intermediate Table Data
5. Delete the package
[Goal]
Delete Package
[Path]
1: Front Desk Code
- Delete handleDelete event to bind delete button (added when editing plan function is implemented)
- Get deleted meal id
- Pop up a query, send a request after confirmation to pass the id to the controller, prompt for the result, and refresh the list if successful
2: Background code
-
SetmealController receives the id, calls the service to delete, and returns the result to the front end
-
SetmealServiceImp
- Determine if used by order
- Error if used
- Not used
- Delete the relationship between the meal and the inspection group first
- Remove meal data
-
SetmealDao
- Query if the ID select count (1) from t_order where setmeal_id= ID exists for this package in the order form?
- delete from t_setmeal where id=#{id}
[Explanation]
5.1.Foreground code
To prevent users from mistaking actions, a prompt to confirm the deletion needs to pop up when clicking the Delete button. Users click Cancel to do nothing. Users click the OK button to submit the deletion request.
5.1.1.Bind Click Event
The click event needs to be bound for the delete button and the current row data is passed as a parameter to the handler
<el-button size="mini" type="danger" @click="handleDelete(scope.row)">delete</el-button>
Method invoked
// delete handleDelete(row) { alert(row.id); }
5.1.2.Pop-up confirmation prompt
Users click on the Delete button to execute the handleDelete method, where the handleDelete method needs to be improved to bring up a confirmation prompt. ElementUI provides a $confirm method to achieve the confirmation prompt popup effect
// delete handleDelete(row) { // alert(row.id); this.$confirm('This action will [permanently delete] the package, Continue or not?', 'Tips', { confirmButtonText: 'Determine', cancelButtonText: 'cancel', type: 'warning', center: true }).then(() => { // Perform deletion }).catch(() => { this.$message({ type: 'info', message: 'Delete cancelled' }); }); }
5.1.3.Send Request
If the user clicks the OK button, he or she needs to send an ajax request and submit the id of the current package as a parameter to the background for deletion
// delete handleDelete(row) { // alert(row.id); this.$confirm('This action will [permanently delete] the package, Continue or not?', 'Tips', { confirmButtonText: 'Determine', cancelButtonText: 'cancel', type: 'warning', center: true }).then(() => { // Delete data using id as query condition axios.get("/setmeal/delete.do?id="+row.id).then((response)=>{ // Result(flag,message,data) returned if(response.data.flag){ this.$message({ type: 'success', message: response.data.message }); }else{ this.$message({ type: 'error', message: response.data.message }); } // Refresh this.findPage(); }).catch((error)=>{ }) }).catch(() => { this.$message({ type: 'info', message: 'Delete cancelled' }); }); }
5.2.Background code
health_common Add Constant Definition
5.2.1. Controller
Add Delete Method in SetmealController
// Delete Package @RequestMapping(value = "/delete") public Result delete(Integer id){ setmealService.deleteById(id); return new Result(true, MessageConstant.DELETE_SETMEAL_SUCCESS); }
5.2.2.Service Interface
Extend Delete Method in SetmealService Service Interface
void deleteById(Integer id) throws HealthException;
5.2.3.Service Implementation Class
Note: It is not possible to delete the meal directly. It is necessary to determine if the current meal is associated with the inspection group or not if it is already associated with the inspection group.
SetmealServiceImpl.java
// Delete Package @Override @Transactional public void deleteById(Integer id) throws HealthException { // Is there an order, if it exists it cannot be deleted int count = setmealDao.findOrderCountBySetmealId(id); if(count > 0){ // This package is already in use on an order and cannot be deleted throw new HealthException("This package is already in use on an order and cannot be deleted!"); } // Delete the relationship between the meal and the inspection group first setmealDao.deleteSetmealCheckGroup(id); // Remove Package setmealDao.deleteById(id); }
5.2.4.Dao interface
Extending methods findSetmealAndCheckGroupCountBySetmealId and deleteById in the SetmealDao interface
/** * The id query for the meal uses the number of individual orders for the meal * @param id * @return */ int findOrderCountBySetmealId(int id); /** * Delete meal information via id * @param id */ void deleteById(int id);
5.2.5.Mapper Mapping File
Extending SQL statements in SetmealDao.xml
<select id="findOrderCountBySetmealId" parameterType="int" resultType="int"> select count(1) from t_order where setmeal_id=#{id} </select> <delete id="deleteById" parameterType="int"> delete from t_setmeal where id=#{id} </delete>
[Summary]
The point to delete the judgement is whether the package was used for an order, not the relationship between the package and the inspection team
Note: Deleted business adds transaction control, deleted interface adds exception declaration