Summary of Health Project day3

Keywords: Java

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]

  1. 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
            }
        }
        
  2. 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

  3. 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]

  1. Make the name of the picture uploaded to Qiniu unique
  2. When the upload component of the elementUI succeeds, the callback handleAvatarSuccess(response) is handled by the elementUI, response=>Result.
  3. 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:

  1. 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
  2. SetmealController receives QueryPageBean, invokes the business service query page Result, wraps it up and returns it to the front end
  3. SetmealServiceImp uses PageHelper paging, has query conditions to achieve fuzzy query splicing, calls dao query, returns PageResult object
  4. 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

Posted by Mardoxx on Tue, 21 Sep 2021 09:21:44 -0700