Health examination center

Intellectual health

Project introduction

Business system of health management organization

Traditional Internet projects (back-end system, front-end wechat web page)

Information that developers should need

​ 1. Requirements specification PRD [including function outline, function details, flow chart, performance requirements], product prototype diagram

​ 2.UI: the prototype drawing is not the final effect drawing, and the UI shall prevail. So if you have it, you need to get it

​ 3. Interface name and other parameters for interfacing with front-end staff

development process

  • Demand analysis: the product personnel do and output PRD (including function outline, function details, flow chart and performance requirements) and product prototype diagram

  • Design (general design and detailed design): the architect does and outputs general design and detailed design (state machine, class diagram, sequence diagram)

  • Coding: programmer, output function code (source code, unit test code of function)

  • Testing: testers, output test reports (test cases [various situations in use], function test reports, performance test reports, security test reports, integration test reports)

  • Operation and maintenance: programmers upgrade and maintain functions

Project structure diagram

  • Project directory structure

  • Project technical support

Problems to be solved

1. Find out the differences among Controller, RestController and ResponseBody (solved)

Project BUG summary

1. Error: version 1.0-SNAPSHOT in the parent project cannot be found

Reason: due to interdependence, the previous dependent package cannot be found during packaging

Solution: first packaging order: domain – > parent project

2. Error reporting: the control layer member variables are normally injected into the space-time pointer

Cause: thread blocking occurred when zk was started

Solution: restart zk and be careful not to stop the cursor. Right click Cancel

3. Error report: business layer member variable injection is null

Most of the things in the business layer are jar packages, so you can inject them directly and automatically

4. Error reporting:

Failed to write HTTP message: 				org.springframework.http.converter.HttpMessageNotWritableException: No converter found for return value of type: class com.wz.result.Result

Reason: the returned result cannot be converted to json normally

Solution: json dependent package is required

  1. The business layer can obtain the results normally and report an error timeout when returning to the control layer

    Reason: network fluctuation is related to your own computer

    Solution: add the timeout duration in both the business layer and the control layer

  2. Dynamic SQL statement error: Java sql. SQLException: Parameter index out of range (2 > number of parameters, which is 1).

    Reasons: 1) comment statements in dynamic sql

    2) strings can only be spliced by concat

    Solution: where code = #{value} or name like CONCAT(CONCAT('%', #{value}), '%')

<select id="findAllCheckItem" resultType="CheckItem" parameterType="string">
      SELECT * FROM t_checkitem
    
    		//Note: the value here must be consistent with the getvalue method name of string. If you want to use other names, use @ param to specify the variable name
    
          <if test="value!=null and value.length>0">
             where  code = #{value} or name like CONCAT(CONCAT('%', #{value}), '%')
          </if>
      ORDER BY id DESC
</select>

7.sql error, Duplicate entry 'xxx' for key 'PRIMARY'

Reason: when operating the database, the primary key of the same data is added or deleted (in the same transaction)

Solution: check whether the logic or sql statement is consistent with the logic

8. Foreground status code 400 background HTTP conversion failed

Reason: the parameters transmitted from the foreground to the background must be consistent with the background @ RequestBody, otherwise an error will be reported

Solution: pass in the parameters required by the background

9. Front end 415 error, not application/json type

Cause: caused by dependency package error

Solution: use the complete json type dependency package

10. When using hashmap of freemaker for storage, you cannot use object to store entity class objects, which will lead to map Put cannot encapsulate an entity class in an entity class

11.interval = window.setInterval(timer,100); Method, the caller method cannot be timer(), otherwise it will be executed only once!!

12. Everything is normal. The permission has been set and confirmed to be removed, but the removed permission can still be operated normally.

Reason: use hasAuthority instead of hasPermission.

Solution: when setting permissions with annotations in the background, use hasAuthority instead of hasPermission.

@PreAuthorize("hasAuthority('CHECKITEM_EDIT')")

13. (followed by a bug) the user does not have the permission but is not blocked and can still be used

Reason: when using spring security security framework, web XML configuration files cannot be scanned at the same time, which will lead to ineffective permissions.

Solution: use the dispatcher scanner to scan all configuration files directly, and you can't use the import tag to import in spring

Summary of project precautions

1. If a dependency that must be inherited is specified in the parent project, it cannot be specified in the child project, otherwise an error will be reported.

2.web. Tags in XML exist in order

3. The bottom layer of Dubbo annotation scanning package will automatically scan component and its sub annotations, so spring scanning package can not be used

[it is recommended to add spring package scanning, because an error will be reported if other spring annotations need to be used]

4. Set Web The XML access path is / must be configured with static resource filtering

5. dao objects in the business layer can only be injected automatically in the way of autowarned, not remotely, otherwise they are null

6. Question: why is new not automatically injected when ssm result object is used?

Not all classes should be managed by the container. Classes created frequently like this are handed over to the container, and the container will crack.

Why is dao not divided into three-tier architecture?

A: it is not necessary to re decompose the network resources occupied by one layer

7. Since the post method is used, you must use @ RequestBody on the parameters of the method to inject automatically

8. The difference between $# of sql statement in Dao: # add '# when compiling, and the other will not. What value is passed will be stored without' [high frequency interview]

9. If the dao is garbled when writing to the database, splice '? characterEncoding=utf8’

10. When @ Service and @ Trasactional are used together in the business layer, you need to specify Interfaceclass or interfaceName for @ Service and generate entity objects in zk for access

11. Why can we use requestBody on the back end to connect json data normally? Because the application/json is specified in the contentType of the front-end page, the bottom layer of the annotation helps us specify it, so we can

12. Most of the front-end methods are asynchronous methods.

13. When using JDBC configuration file, you must add an enhanced suffix to the url item.

14. If the parent class framework is used for remote call, it must be injected with the set method of the member variable, otherwise it will not take effect and will be null

15. When querying mybatis, the total of the query is 1, but the actual query in mybatis is 0, but this 0 is still a record, so the total is 1

16. Trilogy of verification rules

​ 1. Input process verification

​ 2. Submit form verification

​ 3. Background verification background verification if you need to use network remote transmission, such as dubbo, it is written in the control layer. The rest can be in the business layer, which is convenient for packaging and reuse.

  1. Each table must have a clear field meaning!

18. If the value in redis has an expiration time, the redis key still exists after expiration. I just can't get the value of this key. There is a 200ms scheduled cleaner at the bottom of redis to clean up these expired keys

19. In the insert sql statement of mybatis, useGenerate=true keyproperty = "table field name" can replace selectKey to obtain the primary key

Project solving skills

1. If you encounter a jar package conflict, you can choose to delete the updated file of the corresponding jar package (it is recommended to delete all the updated files in the local warehouse)

2. When using transactions in dubbo, the attribute interfaceClass = class name should be used in the service annotation of the business layer Class definition. If it is not defined, the proxy object will be found in zk's registry. Only after it is defined will there be such an object with the same package name in the registry

3.VUE built-in output spring frame this$ message. error/success/info(" ") ;

4. The front-end code has more than one post request parameter, which can be added after the method? It is transmitted in the form of get, and the back end receives it with multiple parameters,? The parameters after are received without @ RequestBody json

5. Search the Maven project on Baidu. The dependency package starts with Maven. The dependency package can be found quickly after

6. In vue, you can assign values to objects of type {} by using ['key']. As a key, it exists with overwrite and no creation. This is a js syntax

    if(vali) { //Verification rules
       let temp = [];  //Store temporary variables

       this.checkitemIds.forEach(item => {  //Check item with variable checked
        temp[temp.length] = {'id': item}; //Since the index is 0, the index length is + 1 for each element added
        });
        this.formData['checkItems'] =temp; //Complete assignment
        // As long as it is an object type, you can use [] for assignment, with overwrite and no creation
        } //Complete assignment 
// As long as it is an object type, you can use [] for assignment, with overwrite and no creation

7. Use freemaker

Precautions: 1 Each loop variable of the required placeholder cannot be empty

​ 2. Placeholder symbols cannot be misspelled

Project specification

1. All exceptions are uniformly received and handled by the control layer. It is better to encapsulate a class to return uniformly

2. If there is string information, try to use static final class to define the call instead of direct hard coding

3. Trilogy verification. The last step is controlled at the control layer to avoid the impact of dubbo remote verification at the business layer on efficiency

Source code analysis

1. The Dubbo package scanning tag will load the Component annotation at the bottom, so if it is only applicable to components, it can be used without using spring package scanning [component is actually the parent of controller, service and repository]

2. If you want to inject private member variables in the parent class, AutoWare supports injection in the parent class

However, remote injection using dubbo is not allowed, because the source code is limited, and remote injection can only be carried out by the method starting with the set method

Therefore: define member variables and use the set method to realize injection

3. Every time ZK is used, the node of dubbo will be generated. If interfaceName (full pathname) / interfaceClass (class name). Class) is not specified, it will?

4. There are two ways to get parameter names at the bottom of mybatis

@Param and / / parameter names. If annotations are not used, the JVM will first try to use this name at the bottom If the class file is found, it can be used. If it is not found, it will be parsed with the name arg0 arg1. Whether it can be found is related to the computer.

Unified specification. Annotation should be used when using a single variable name

5. The bottom layer of the start method of PageHelper paging plug-in is the threadLocal shared memory area

Therefore, when searching the method, you will go to the shared area to get the seemingly irrelevant current page and the size of each page

Then, the limit keyword will be added to mybatis for query

Phase I – back office development

Development module function

1) Check item / group management module

Import databases and forms

		The character set must be specified when creating the database utf8mb4  Function: support when using mobile terminal emoj Four characters

Use PMD to explain the meaning and operation of each field in each table (specification)

The database table varchar (32) stores 32 letters, 16 characters (2 bytes) and 8 expressions (4 bytes)

Import entity class

Import public resources

​ 1. Returns the status type object of the front end

​ 2. Returns the result object of the front end

​ 3. Paging object [total number, current page result]

​ 4. Query objects by criteria

​ 5. Basic static resources

PowerDesigner tabulation design

View the PDF of the first day of the project and the specific steps

Is an ER entity relationship diagram design software, referred to as PDM (database design diagram)

It is convenient to analyze and design the system, so as to make data flow chart, physical data model (database table design), conceptual data model and object-oriented model.

1. Tabulation process

Mysql 5.0 should be used to create tables, otherwise sql yog creation will report an error

code – indicates table name and field name

p -- primary key

identity – self increment of primary key

2. Export sql table

Foreign keys should be specified in the design, but they are filtered out when creating the database

​ 1. database in menu bar

​ 2.create database

​ 3. Option -- > uncheck the foreign key

3. Reverse engineering

Parse the table creation file into a table diagram structure and display it on the software

​ file —reverse --database

4. Generate database report file

Generate a web version of the overall table data is intuitive, you can view the structure or information of all tables in it

report - report wizard

The new datagroup software is easy to use and needs to be cracked

datafactory, stress testing software. Mass production data for database tables

Front end UI design

To use any component, you need to create an object first

​ new Vue ({

​ el : " "

})

Layout container

General layout of container

Resolution:

In el - main, the remaining page space of the current row is automatically filled

The attribute definition of the container is one line for each child tag

If you want to keep aside and main in the same line, you need to use container to store them together

The side on the left and right are set in the order of sub labels

    <!--Import previous vue Component can take effect-->
    <link rel="stylesheet" href="element-ui/lib/theme-chalk/index.css">
    <script src="element-ui/vue.js"></script>
    <!-- introduce ElementUI Component library -->
    <script src="element-ui/lib/index.js"></script>



<el-container>
    <el-header>Header</el-header>

    <el-container>
		  <!--It can be left placed in the same container-->
        <el-aside width="200px">Aside</el-aside>

        <el-container>
            <el-main>Main</el-main>
            <el-footer>Footer</el-footer>
        </el-container>
        <!--It can be placed right in the same container-->
        <el-aside width="200px">Aside</el-aside>
    </el-container>
</el-container>

drop-down menu

Objective: to learn the properties and types that components focus on

size

trigger

divided in the sub label can add a dividing line to each sub option

<el-container>
    <el-aside width="200px">
        <el-menu>
            <el-submenu v-for="menu in menuList" :index="menu.path">
                <template slot="title">
                    <i class="fa" :class="menu.icon"></i>
                    {{menu.title}}
                </template>
                <template v-for="child in menu.children">
                    <el-menu-item :index="child.path">
                        <a :href="child.linkUrl" target="right">{{child.title}}</a>
                    </el-menu-item>
                </template>
            </el-submenu>
        </el-menu>
    </el-aside>
    <el-container>
        <iframe name="right" class="el-main" src="ordersetting.html" width="100%" height="580px" frameborder="0"></iframe>
    </el-container>
</el-container>
<script>
    new Vue({
        el: '#app',
        data:{
            menuList:[ //Cycle the menu to display the corresponding data and jump function
                
                {
                    "path": "1",
                    "title": "workbench",
                    "icon":"fa-dashboard",
                    "children": []
                },
                {
                    "path": "2",
                    "title": "Member management",
                    "icon":"fa-user-md",
                    "children": [
                        {
                            "path": "/2-1",
                            "title": "Member files",
                            "linkUrl":"member.html",
                            "children":[]
                        },
                        {
                            "path": "/2-2",
                            "title": "Upload physical examination",
                            "children":[]
                        },
                        {
                            "path": "/2-3",
                            "title": "Membership statistics",
                            "linkUrl":"all-item-list.html",
                            "children":[]
                        },
                    ]
                },
                {
                    "path": "3",
                    "title": "Booking Management ",
                    "icon":"fa-tty",
                    "children": [
                        {
                            "path": "/3-1",
                            "title": "Subscribe List ",
                            "linkUrl":"ordersettinglist.html",
                            "children":[]
                        },
                        {
                            "path": "/3-2",
                            "title": "Reservation settings",
                            "linkUrl":"ordersetting.html",
                            "children":[]
                        },
                        {
                            "path": "/3-3",
                            "title": "Package management",
                            "linkUrl":"setmeal.html",
                            "children":[]
                        },
                        {
                            "path": "/3-4",
                            "title": "Inspection team management",
                            "linkUrl":"checkgroup.html",
                            "children":[]
                        },
                        {
                            "path": "/3-5",
                            "title": "Inspection item management",
                            "linkUrl":"checkitem.html",
                            "children":[]
                        },
                    ]
                },
                {
                    "path": "4",
                    "title": "Health assessment",
                    "icon":"fa-stethoscope",
                    "children":[
                        {
                            "path": "/4-1",
                            "title": "TCM Constitution identification",
                            "linkUrl":"all-medical-list.html",
                            "children":[]
                        },
                    ]
                },
                {
                    "path": "5",     //Route path corresponding to the menu item
                    "title": "statistical analysis",     //Menu item name
                    "icon":"fa-heartbeat",
                    "children":[//Whether there is a submenu. If not, it is []
                        {
                            "path": "/5-1",
                            "title": "Workload statistics",
                            "linkUrl":"all-medical-list.html",
                            "children":[]
                        }
                    ]
                }
            ]
        }
    });
    $(function() {
            var wd = 200;
            $(".el-main").css('width', $('body').width() - wd + 'px');
    });
</script>

Navigation menu

View on the official website

Message message prompt

See more on the official website

Built in object this$ Message is activated using the event success/erorr/info/warning

Here, take the callback function as an example

axios.post("/Jump",this.formData).then((resp)=>{
//Judge callback result
//If the result is true
if(resp.data.flag){
//Prompt, successful
    this.$message.success(resp.data.message) ;  //Use pop-up built-in objects
    //Refresh the page to display all the data of the inspection items
    this.pagination.currentPage=1;
    this.findPage();
}else {
    //Prompt, error
    this.$message.error(resp.data.message) ;
//Refresh the page to display all the data of the inspection items
    this.pagination.currentPage=1;
    this.findPage();
}
})

form

Table component functions

Template slot scope = "'scope' scope slots are defined in the sub label template

//1. Set row fixation 
//2. Zebra stripes 
//3. Bidirectional binding of datalist variables
<el-table size="small" current-row-key="id" :data="dataList" stripe highlight-current-row> 
    <el-table-column type="index" align="center" label="Serial number"></el-table-column>
    <el-table-column prop="code" label="Item code" align="center"></el-table-column>
    <el-table-column prop="name" label="entry name" align="center"></el-table-column>
    <el-table-column label="Applicable gender" align="center">
        <template slot-scope="scope">
            <span>{{ scope.row.sex == '0' ? 'unlimited' : scope.row.sex == '1' ? 'male' : 'female'}}</span>
        </template>
    </el-table-column>
    <el-table-column prop="age" label="Applicable age" align="center"></el-table-column>
    <el-table-column prop="remark" label="Project description" align="center"></el-table-column>
    <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>
</el-table>
  • Zebra stripe different color

  • Change of background color: row class name = "tableRowClassName"

    //Provide method to change color
    tableRowClassName({row, rowIndex}) {
            if (rowIndex === 1) {
              return 'warning-row';
            } else if (rowIndex === 3) {
              return 'success-row';
            }
            return '';
          }
        }
    
  • The header is fixed, and the height of the table can be set. Height = "250"

  • Column fixed / frozen. Set fixed on the column. If it is right fixed, it is fixed = 'right'

  • Table generation sequence number

    <el-table-column type="index" width="50"></el-table-column>  // type="index"
    
  • Radio highlight current row for table columns

  • Multiple selection of tables

    <el-table-column type="selection" width="55"> </el-table-column>// type="selection"
    
  • The table is sorted by column header, and sortable can be added

label

View on the official website

form

Layout of forms

Verification of forms

​ 1. Real time verification

​ 2. Submit verification

//Define validation rules in the data attribute
//Validate rules in form
 <!--Set reference name, bidirectional binding formdata Form content, specifying rules-->
			  <el-form ref="dataEditForm" :model="formData"  label-position="right"  label-width="100px" :rules="rules">
                    rules: {
                        name: [
                            { required: true, message: 'Please enter the activity name', trigger: 'blur' },
                            { min: 3, max: 5, message: 'The length is between 3 and 5 characters', trigger: 'blur' }
                        ],
                        region: [
                            { required: true, message: 'Please select an active area', trigger: 'change' }
                        ]
                    }    
                    
    //Syntax for input verification
    this.$refs['form'].validate(function(valid){
        
    });
	//Clear check
	this.$refs["dataAddForm"].resetFields();
    this.$refs["dataAddForm"].clearValidate();

​ 3. Form division

The form can be divided into 24 copies and the length can be defined separately

<el-form ref="dataEditForm" :model="formData"  label-position="right"  label-width="100px" :rules="rules">
    		//This behavior is a group and bound with the span attribute of the column label. It is recommended to divide it with 24 as an integer
                <el-row>
                    <el-col :span="12">      
                        <!--Set verification object-->
                        <el-form-item label="code" prop="code" >
                            <el-input v-model="formData.code"/>
                        </el-form-item>
                    </el-col>
                    <el-col :span="12">
                        <!--Set verification object-->
                        <el-form-item label="name" prop="name">
                            <el-input v-model="formData.name"/>
                        </el-form-item>
                    </el-col>
                </el-row>
    
    
    
                <el-row>
                    <el-col :span="12">
                        <el-form-item label="Applicable 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">
                        <!--Set verification object-->
                        <el-form-item label="Mnemonic code" prop="helpCode">
                            <el-input v-model="formData.helpCode"/>
                        </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>

Paging component

  • sizes, how many pieces per page
  • total
  • prev
  • pager, quick click page number
  • next
  • jumper, jump page
<div class="pagination-container">
    <el-pagination
        class="pagiantion"  //Built in class style
        @current-change="handleCurrentChange" //Activation method when clicking paging
        :current-page="pagination.currentPage" //Current page
        :page-size="pagination.pageSize"	//Size per page
        layout="total, prev, pager, next, jumper"//Clickable buttons
        :total="pagination.total"  				//PageCount 
    >
    </el-pagination>
</div>

//Method name and content are defined by yourself
handleCurrentChange(currentPage) {
     this.pagination.currentPage=currentPage; //Modify current page
     this.pagination.queryString=null;//Reset query box content
       this.findPage();//Call query
 },

Code generation tool

Function: generate code in DAO layer, with the name of [mybatis generator] (the free mybatis plug-in has integrated this graphical function)

Steps:

​ 1. Import dependencies in build/plugins

​ 2. Create configuration file [in the project that needs to generate code]

​ 3. Connect to database

Seven cattle cloud upload pictures

The image server has a hot image cache and can add a CDN cache (very expensive) to form a set of image response architecture

– upload the web page to your own server, and the server will forward it to the image server. The next visit will be directly obtained from the image server (qiniu)

API usage: help document of qiniu cloud SDK

Usage details:

1. Upload objects and import dependencies in the control layer configuration file

<!--File upload component-->
<bean id="multipartResolver"
     class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    <property name="maxUploadSize" value="104857600" />
    <property name="maxInMemorySize" value="4096" />
    <property name="defaultEncoding" value="UTF-8"/>
</bean>
  <quartz.version>2.2.1</quartz.version>
  <commons-fileupload.version>1.3.1</commons-fileupload.version>
<!-- File upload component -->
<dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
    <version>${commons-fileupload.version}</version>
</dependency>
<dependency>
    <groupId>org.quartz-scheduler</groupId>
    <artifactId>quartz</artifactId>
    <version>${quartz.version}</version>
</dependency>
<dependency>
    <groupId>org.quartz-scheduler</groupId>
    <artifactId>quartz-jobs</artifactId>
    <version>${quartz.version}</version>
</dependency>
<dependency>
    <groupId>com.sun.jersey</groupId>
    <artifactId>jersey-client</artifactId>
    <version>1.18.1</version>
</dependency>
<dependency>
    <groupId>com.qiniu</groupId>
    <artifactId>qiniu-java-sdk</artifactId>
    <version>7.2.0</version>
</dependency>

2. Add two necessary methods on the page: check before uploading and display after uploading

 //The hook after the file is uploaded successfully. The response is the value returned by the server, and the file is the js object encapsulated by the currently uploaded file
           handleAvatarSuccess(response, file) {   //The response here is the returned result object, which can be used directly attribute
               this.imageUrl=response.data;
               this.$message({
                   type:response.flag?"success":"error",
                   message:response.message,
                   name:response.name
               });
               if(response.flag){
                   //Preview the file just uploaded
                   this.imageUrl = "http://puco9aur6.bkt.clouddn.com/"+response.data; / / assign a value to the url, and the binding is displayed
                   this.formData.img = response.data;//Assign the file name to the model data for form submission
               }
           },
           //Execute before uploading pictures
           beforeAvatarUpload(file) {
              console.log(file);   //Print file content to console

 const isJPG = file.type === 'image/jpeg';     //The image format is jpeg
 const isLt2M = file.size / 1024 / 1024 < 2;   //Size less than 2M
 if (!isJPG) {
this.$message.error('Upload package pictures can only be JPG format!');
 }
 if (!isLt2M) {
this.$message.error('Upload package picture size cannot exceed 2 MB!');
 }
 return isJPG && isLt2M;    
           },

3. Upload the function of each variable of the component

action: the background operation will be executed every time there is an upload behavior

 <el-upload
            class="avatar-uploader"
            <!--After the pre upload callback, the upload address of the constrained file-->
            action="/setmeal/upload.do"
			<!--Auto upload-->
            :auto-upload="true"
			<!--The parameter names of the backend receiving this file must be consistent-->
            name="imgFile"
            :show-file-list="false"
			<!--Callback function after successful upload-->
            :on-success="handleAvatarSuccess"
			<!--Callback before upload-->
            :before-upload="beforeAvatarUpload">
	 <!--The preview effect of the picture after the picture is uploaded successfully-->
     <img v-if="imageUrl" :src="imageUrl" class="avatar">   //If the image is uploaded successfully, the value of the url will be assigned directly
     <i v-else class="el-icon-plus avatar-uploader-icon"></i>//Otherwise, it will not be displayed, and the picture set by the pair will be used instead of "+" here
</el-upload>

4. Background file upload control layer

//File upload
@RequestMapping("/uploadFile")
public Result updoadFile(@RequestParam("imgFile") MultipartFile imgFile){
    String originalFilename = imgFile.getOriginalFilename();//original filename
    int index = originalFilename.lastIndexOf(".");  //get. Index of
    String suffix = originalFilename.substring(index);  //Intercept according to the index jpg
    String fileName = UUID.randomUUID().toString() + suffix; //Generate a file name splice jpg
    //Save the picture to qiniu cloud
    try{
        //Call tool class
        QiniuUtils.upload2Qiniu(imgFile.getBytes(),fileName);
        //After the file is uploaded successfully, the file name needs to be saved in redis
        jedisPool.getResource().sadd(RedisConstant.SETMEAL_PIC_RESOURCES,fileName);
        return new Result(true, MessageConstant.PIC_UPLOAD_SUCCESS,fileName);
    }catch (Exception e){
        e.printStackTrace();
        return new Result(false,MessageConstant.PIC_UPLOAD_FAIL);
    }
}

5. Click to confirm the business layer after submitting the form

After the database is successfully inserted, it is submitted to redis in the form of stream for cache saving, mainly to save the name

        //Create result object
        Result result = new Result();

        //Insert package
        int meal =mealDao.insertGroup(setmeal);
        
        //Get new object id
        Integer id = setmeal.getId();

        //Determine whether the insertion is successful
        //=0 indicates that the insertion failed
        if(meal==0){
            result.setFlag(false);
            result.setMessage(MessageConstant.EDIT_CHECKGROUP_FAIL);
            return  result;
        }

        //If the package is successfully inserted, the corresponding picture will be saved in redis. After confirmation, it will be submitted to redis for caching
        jedisPool.getResource().sadd(RedisConstant.SETMEAL_PIC_DB_RESOURCES,setmeal.getImg());//Automatically inject redispool

Storage scheme

Scheme I

	nginx  Reverse proxy is a simple high-performance server, which prefers static resource deployment tomcat Prefer dynamic resource deployment

Scenario: the image data that the enterprise website needs to use

Scheme II:

Open source distributed storage systems, such as Fastdfs (ALI open source), HDFS

Scenario: pictures uploaded by users during use. Avatar, circle of friends, pictures, etc.

Scheme III:

Cloud storage. Such as seven cattle cloud, baidu cloud. High cost

Scene: a large project, such as Jingdong Taobao.

authentication

Use steps:

1) Upload

​ 1. Get local server object

​ 2. Create a seven cow cloud object

​ 3. Authentication (warehouse, warehouse AKey, SKey)

​ 4. Obtain authority authentication

​ 5. Upload (no key is specified, and the hash value is used as the file name by default)

​ 6. Analyze upload results

2) Delete

​ 1. Get local server object

​ 2. Create a seven cow cloud object

​ 3. Authentication (warehouse, warehouse AKey, SKey)

​ 4. Specifies the file name to delete

​ 5. Transmission instruction

​ 6. Analytical results

Timer Quartz

Redis needs to provide cache service support during this period

Quartz definition: open source distributed timed task scheduling framework

Create a custom job Timer class and create a logical method to be executed

configuration file

​ 1. Add timer class to spring container

​ 2. The configuration specifies the method to be used (it must be public, otherwise it may not be called)

​ 3. Create trigger

​ 4. Create trigger scheduling factory

use

​ 1. Import package (dependent on spring package)

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context-support</artifactId>
        <version>5.0.2.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-tx</artifactId>
        <version>5.0.2.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.quartz-scheduler</groupId>
        <artifactId>quartz</artifactId>
        <version>2.2.1</version>
    </dependency>
    <dependency>
        <groupId>org.quartz-scheduler</groupId>
        <artifactId>quartz-jobs</artifactId>
        <version>2.2.1</version>
    </dependency>
</dependencies>

​ 2. Write the implementation logic of the job and use it as a war package

/**
 * Customize tasks and regularly clean up garbage pictures
 */
public class ClearImgJob {
    @Autowired
    private JedisPool jedisPool;

    //Clean up pictures
    public void clearImg(){
        System.out.println("Regularly clean up garbage pictures");
        Set<String> set = jedisPool.getResource().sdiff(RedisConstant.SETMEAL_PIC_RESOURCES, RedisConstant.SETMEAL_PIC_DB_RESOURCES);
        if(set != null){
            for (String fileName : set) {
                System.out.println("Regularly clean up garbage pictures: " + fileName);
                //Delete files from qiniu ECS according to the image name
                QiniuUtils.deleteFileFromQiniu(fileName);
                //Delete picture name from redis collection
                jedisPool.getResource().srem(RedisConstant.SETMEAL_PIC_RESOURCES,fileName);
            }
        }
    }
}

​ 3. to configure

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                  http://www.springframework.org/schema/beans/spring-beans.xsd
                  http://www.springframework.org/schema/mvc
                  http://www.springframework.org/schema/mvc/spring-mvc.xsd
                  http://code.alibabatech.com/schema/dubbo
                  http://code.alibabatech.com/schema/dubbo/dubbo.xsd
                  http://www.springframework.org/schema/context
                  http://www.springframework.org/schema/context/spring-context.xsd">
    
    <!-- Register custom Job -->
    <bean id="jobDemo" class="com.itheima.jobs.JobDemo"></bean>
    
    <!-- register JobDetail,The function is responsible for calling the specified through reflection Job -->
    <bean id="jobDetail"
          class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
        <!-- Inject target object -->
        <property name="targetObject" ref="jobDemo"/>
        <!-- Injection target method -->
        <property name="targetMethod" value="run"/>
    </bean>
    
    <!-- Register a trigger and specify the time when the task is triggered -->
    <bean id="myTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
        <!-- injection JobDetail -->
        <property name="jobDetail" ref="jobDetail"/>
        <!-- Specifies the time to trigger, based on Cron expression -->
        <property name="cronExpression">
            <value>0/10 * * * * ?</value>
        </property>
    </bean>
    
    <!-- Register a unified scheduling factory to schedule tasks through this scheduling factory -->
    <bean id="scheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
        <!-- Inject multiple triggers -->
        <property name="triggers">
            <list>
                <ref bean="myTrigger"/>
            </list>
        </property>
    </bean>
</beans>

Cron expression

The last of the seven positions can be separated without spaces

For example: execute 0 / 10 * * every ten seconds?

Execute 0 0 2 * * every day at 2 a.m?

0 0 / 5 3-5 * * every 5 minutes at 3-5 every morning?

name Is it necessary Allowable value Special characters
second yes 0-59 , - * /
branch yes 0-59
Time yes 0-23
day yes 1-31
month yes 0-11
week yes 1-7 or SUN-SAT
year no Empty or 1970-2099

Apache POI upload file

It can operate all Microsoft office automation software, but it is more used to operate excel tables

Function: batch data upload / export

Introductory case

Note: 1 When reading cells, if the types are inconsistent, an error is reported

​ 2. get data

Get rows (when getting the number of rows / cells, in order to remove the header, the row index starts from 1, and when the ordinary for loop traversal is < =, the cell index starts from 0)

Get the cell (Note: if the cell is deleted after assignment, it will also be read, and the value is "")

​ 3. flush() forcibly flushes the cache data in memory to disk for storage

​ 4. When compressed after excel 07, it is stored in xml file with SXSSworkbook (it does not occupy memory and does not support formulas)

Xssf workbook reads excel into memory and organizes the structure tree (occupies memory, but supports excel formula calculation)

Guide Package (only excel is supported here)

<!--poi-->
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi</artifactId>
</dependency>
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
</dependency>

Read data

//Get the poi object and read the file into memory
XSSFWorkbook sheets = new XSSFWorkbook("D:\\poi.xlsx");

//Get sheet page getsheetat / getsheetname
//Get the first table
XSSFSheet sheet = sheets.getSheetAt(0);

//Loop each line
for (Row row : sheet) {
    //Cycle through each cell of each row
    for (Cell cell : row) {
        //The data type read by conversion is string
        cell.setCellType(Cell.CELL_TYPE_STRING);
        //Get the cell information
        String value = cell.getStringCellValue();
        //output
        System.out.print(value);
      }
}

Write data

//Create poi object
XSSFWorkbook workbook = new XSSFWorkbook();

//Create worksheet
XSSFSheet sheet = workbook.createSheet("surface");

//Create first row
XSSFRow row = sheet.createRow(0);

//Create a cell for this row
XSSFCell cell = row.createCell(0);

//Assign a value to this row
cell.setCellValue("aa11");

//Create first row
XSSFCell cell_1 = row.createCell(1);

//Assign a value to this row
cell_1.setCellValue("bb11");

//Create output stream
FileOutputStream out = new FileOutputStream("D:\\testPOI.xlsx");

//Write out excel in memory`
workbook.write(out);

//Refresh memory
out.flush();

//Closed flow
out.close();

//Close excel
workbook.close();

Tool class

The method of judging the type of cell is available, and others should be used with caution

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.web.multipart.MultipartFile;

public class POIUtils {
    private final static String xls = "xls";
    private final static String xlsx = "xlsx";
    private final static String DATE_FORMAT = "yyyy/MM/dd";
    /**
     * Read into excel file and return after parsing
     * @param file
     * @throws IOException
     */
    //Get each row of data in the excel file
    public static List<String[]> readExcel(MultipartFile file) throws IOException {
        //audit file
        checkFile(file);

        int a = 0;//Remove duplicate lines and ignore

        //Get Workbook Workbook object
        Workbook workbook = getWorkBook(file);

        //Create a return object, take the values in each row as an array, and return all rows as a collection
        List<String[]> list = new ArrayList<String[]>();

        //The getWorkBook method may return null
        if(workbook != null){

            //Traverse several tables (table index starts from 0)
            for(int sheetNum = 0;sheetNum < workbook.getNumberOfSheets();sheetNum++){
                //Get each table in turn
                Sheet sheet = workbook.getSheetAt(sheetNum);
                //Judge that the table is null and directly enter the next cycle
                if(sheet == null){
                    continue;
                }

                int a1= 0;//Remove duplicate lines and ignore

                //Gets the start line of the current sheet
                int firstRowNum  = sheet.getFirstRowNum();

                //Gets the end line of the current sheet
                int lastRowNum = sheet.getLastRowNum();

                //Loop all rows except the first row (because there is a header and the row index starts from 1)
                for(int rowNum = firstRowNum+1;rowNum <= lastRowNum;rowNum++){
                    //Get current row
                    Row row = sheet.getRow(rowNum);

                    //Judge whether the behavior is null and directly enter the next cycle
                    if(row == null){
                        continue;
                    }

                    //Get the first cell of the current row (the rule is implemented according to getLastCellNum method)
                    int firstCellNum = row.getFirstCellNum();

                    //Gets the number of columns in the current row
                    //getLastCellNum: get the last number of columns of the row (cells modified and later reset to null are also counted as one column)
                    //getPhysicalNumberOfCells: get the number of physical columns of the row (the last column cell with value at present)
                    //short lastCellNum = row.getLastCellNum();
                    //Gets how many cells the current row actually has
                    int lastCellNum = row.getPhysicalNumberOfCells();

                    int a3 = 0;//Remove duplicate lines and ignore

                    //Save the actual number of cells into
                    String[] cells = new String[row.getPhysicalNumberOfCells()];

                    //Loop current row
                    for(int cellNum = firstCellNum; cellNum < lastCellNum;cellNum++){
                        Cell cell = row.getCell(cellNum);//Gets the object of the current cell
                        cells[cellNum] = getCellValue(cell);//Determine the type of value of the object and store it in the array after conversion
                    }
                    list.add(cells);//Add array results to the collection
                }
            }
            workbook.close();
        }
        return list;
    }

    //Verify whether the file is legal
    public static void checkFile(MultipartFile file) throws IOException{
        //Determine whether the file exists
        if(null == file){
            throw new FileNotFoundException("File does not exist!");
        }
        //Get file name
        String fileName = file.getOriginalFilename();
        //Determine whether the file is an excel file
        if(!fileName.endsWith(xls) && !fileName.endsWith(xlsx)){
            throw new IOException(fileName + "no excel file");
        }
    }

    //Judge which format it ends in and return the corresponding data type object
    public static Workbook getWorkBook(MultipartFile file) {
        //Get file name
        String fileName = file.getOriginalFilename();
        //Create a Workbook Workbook object that represents the entire excel
        Workbook workbook = null;
        try {
            //Get the io stream of excel file
            InputStream is = file.getInputStream();
            //Different Workbook implementation class objects are obtained according to different file suffixes (xls and xlsx)
            if(fileName.endsWith(xls)){
                //2003
                workbook = new HSSFWorkbook(is);
            }else if(fileName.endsWith(xlsx)){
                //2007
                workbook = new XSSFWorkbook(is);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return workbook;
    }
    
    
    
    //Judge what type of cell is available and use it with caution
    public static String getCellValue(Cell cell){
        //Judgment is null
        String cellValue = "";
        if(cell == null){
            return cellValue;
        }

        //If the current cell content is of date type, special processing is required
        CellStyle cellStyle = cell.getCellStyle();

        String dataFormatString = cell.getCellStyle().getDataFormatString();
        if(dataFormatString.equals("m/d/yy")){
            //MM DD YY -- > MM DD YY
            cellValue = new SimpleDateFormat(DATE_FORMAT).format(cell.getDateCellValue());
            return cellValue;
        }

        //Read the number as a String to avoid reading 1 to 1.0
        if(cell.getCellType() == Cell.CELL_TYPE_NUMERIC){
            cell.setCellType(Cell.CELL_TYPE_STRING);
        }

        //Judge the type of data
        switch (cell.getCellType()){
            case Cell.CELL_TYPE_NUMERIC: //number
                cellValue = String.valueOf(cell.getNumericCellValue());
                break;
            case Cell.CELL_TYPE_STRING: //character string
                cellValue = String.valueOf(cell.getStringCellValue());
                break;
            case Cell.CELL_TYPE_BOOLEAN: //Boolean
                cellValue = String.valueOf(cell.getBooleanCellValue());
                break;
            case Cell.CELL_TYPE_FORMULA: //formula
                cellValue = String.valueOf(cell.getCellFormula());
                break;
            case Cell.CELL_TYPE_BLANK: //Null value
                cellValue = "";
                break;
            case Cell.CELL_TYPE_ERROR: //fault
                cellValue = "Illegal character";
                break;
            default:
                cellValue = "unknown type";
                break;
        }
        return cellValue;
    }
}

File upload vue

<!--Upload the file to the back end and directly perform logical judgment and save operation-->
<!--It will be executed before uploading beforeUpload Method, for true To access the backend-->
<el-upload action="/ordersetting/uploadFile"  //Call the method of back-end control
           name="imgFile"					  //The front-end and back-end names must be consistent and received with @ RequestParam("imgFile") annotation
           :show-file-list="false"			  
           :on-success="handleSuccess"		  //Callback function after successful execution of action backend method
           :before-upload="beforeUpload"	  //Callback function before uploading (logical verification callback function after the user selects the picture)
            >
    <el-button type="primary">Upload file</el-button>
</el-upload>

Business layer insertion

@Override
//Add and upload files, batch operation
public Result add(List<OrderSetting> list) {

    //Delete first and then insert. If there is any exception, it will directly return to batch failure
    try {
        orderSettingDao.deleteOrderSetting(list);  //If the list is deleted, no error will occur and the number of rows affected is 0
        orderSettingDao.insertOrderSetting(list);   //insert
        return new Result(true,MessageConstant.IMPORT_ORDERSETTING_SUCCESS);
    } catch (Exception e) {
        e.printStackTrace();
        return new Result(true,MessageConstant.IMPORT_ORDERSETTING_FAIL);
    }
}

calendar

When the front-end parsing code is inconsistent with the fields in the database, you can use map to encapsulate and return, because there is no directly available pojo and you are lazy.

Batch add data

Reservation settings

//Built in method to convert date format
this.formatDate(day.getFullYear(),day.getMonth()+1,day.getDate())

Phase II - mobile terminal development

Package cascade query

ResultMap multilevel associative query

When there is a cascading query of user-defined POJO type in the encapsulated POJO or the fields are inconsistent with pojp, it is necessary to use resultMap for mapping and encapsulation

Query help documents on the official website of mybatis: https://mybatis.org/mybatis-3/zh/index.html

Two ways

​ 1. Pure code parsing query sql resultType circular query multiple times, affecting performance?

Parsing: each cycle requires a query, which is a simple sql connection statement

//Query package details according to package ID (package basic information, inspection group information corresponding to the package, inspection item information corresponding to the inspection group)
    public Setmeal findById2(int id) {
        Setmeal setmeal = setmealDao.findById(id);
        if(setmeal!=null) {
            // select b.* from t_setmeal_checkgroup a LEFT JOIN t_checkgroup b on a.checkgroup_id=b.id where a.setmeal_id=#{id}
            List<CheckGroup> checkGroups = checkGroupDao.findBySetmealId(id);
            for(CheckGroup group : checkGroups){
                // select b.* from t_checkgroup_checkitem a LEFT JOIN t_checkitem b on a.checkitem_id=b.id where a.checkgroup_id=#{id}
                List<CheckItem> checkItems = checkItemDao.finByGroupId(group.getId());
                group.setCheckItems(checkItems);
            }
            setmeal.setCheckGroups(checkGroups);
        }
    }

​ 2. Cascade Association resultMap

resultMap attribute:

1) how to map pojo one by one? What are the usage scenarios of javatype and JDBC type?

2) inheritance characteristics

be careful:

1) when making the front-end page, you cannot use the table tag, because the page refresh will not be displayed uniformly until all table data are read, so you can replace it with div, li, and other tags. Avoid network jam. When the data is too large, it will be white when opening the web page

1. Page refresh starts to access data asynchronously

window.location.toString() key statement to obtain the string information of the current web address

 mounted(){
            //Get the string information of the web address
            // http://localhost:81/pages/setmeal_detail.html?id=5&name=wz
            var page = window.location.toString();

            //According to? Perform segmentation
            var target = page.split("?");

            //The [1] after segmentation is? Subsequent information
            // id=5&name=wz
            //Get [1] and divide it according to & to get an array
             var arr = target[1].split("&");

            //Traversal array id=5, name=wz
            for(let i = 0 ;i < arr.length;i++){

            //Each value should be segmented according to = to obtain array [0] ID [1] 5
               let num = arr[i].split("=");
            //Judge whether [0] is an id. if so, the result of [1] will be returned
                if(num[0]=id){
                    //As long as you enter the page, you will send an asynchronous request to query all the information of the package and display it on the page
                    axios.post("/setmeal/getAllInfoById?id=" + num[1]).then((response) => {
                        if(response.data.flag){
                            this.setmeal = response.data.data[0];
                            this.imgUrl = 'http://qekirsm87.bkt.clouddn.com/' + this.setmeal.img;
                        }
                    });
                }
            }

2. Call dao at the beginning of the business layer and return a package object

//Front page - query all inspection groups and inspection items
@Override
public Result getCheckGroupsAndCheckItems(String id) {

    //Call dao cascade query
   Setmeal setmeal = mealDao.getCheckGroupsAndCheckItemsInMeal(id);

    if(setmeals!=null){
        return new Result(true,MessageConstant.GET_SETMEAL_LIST_SUCCESS,setmeals);
    }

    //Return results
    return new Result(false,MessageConstant.GET_SETMEAL_LIST_FAIL);
}

3. dao of package

Analysis: 1 Enter the getCheckGroupsAndCheckItemsInMeal method to query the package information. The query results are encapsulated into the resultMap of getMeal

​ 2. Due to the inheritance relationship, all fields can be completely encapsulated into the Setmeal object

​ 3. Execute cascading query field checkGroups

<mapper namespace="com.wz.dao.MealDao">
    <!--The result set of package query is inherited by the inspection group-->
    <resultMap id="baseMealResultMap" type="Setmeal">
        <id column="id" property="id"/>
        <result column="name" property="name"/>
        <result column="code" property="code"/>
        <result column="helpCode" property="helpCode"/>
        <result column="sex" property="sex"/>
        <result column="age" property="age"/>
        <result column="price" property="price"/>
        <result column="remark" property="remark"/>
        <result column="attention" property="attention"/>
        <result column="img" property="img"/>
    </resultMap>

    <!--Cascade query of inspection group for query results of this package-->
    <resultMap id="getMeal" type="SetMeal" extends="baseMealResultMap">
        <!--Because it is a collection type, use collection-->
        <collection
                property="checkGroups"
                ofType="CheckGroup"
                column="id"
                select="com.wz.dao.CheckGroupDao.findCheckGroupAndItemByGroupId"
        />
    </resultMap>

    <!--Front page,Query all check items and groups of the package-->
    <select id="getCheckGroupsAndCheckItemsInMeal" resultMap="getMeal">
        select * from t_setmeal where id=#{id}
    </select>
</mapper>

4. dao of inspection team

Analysis: 1 Called by the upper layer, enter in the findCheckGroupAndItemByGroupId method to start querying the inspection group information.

The query results are encapsulated into the resultMap of getGroup.

​ 2. Due to the inheritance relationship, all fields can be completely encapsulated into the CheckGroup object

​ 3. Execute the cascade query field checkItems. Here is a list collection, but the bottom layer will call each element separately and the next layer of sql statements will be called

<mapper namespace="com.wz.dao.CheckGroupDao">
    <!--Check the mapping configuration of the group-->
    <resultMap id="baseGroupResultMap" type="CheckGroup">
        <id column="id" property="id"/>
        <result column="name" property="name"/>
        <result column="code" property="code"/>
        <result column="helpCode" property="helpCode"/>
        <result column="sex" property="sex"/>
        <result column="remark" property="remark"/>
        <result column="attention" property="attention"/>
    </resultMap>

    <!--Setting of cascade query check items for this check group,Here is a collection id,Will be called down in turn-->
    <!--So will id=5 Encapsulate one CheckItem,id=6 Encapsulate one CheckItem-->
    <resultMap id="getGroup" type="CheckGroup" extends="baseGroupResultMap">
        <collection
                property="checkItems"
                ofType="CheckItem"
                column="id"
                select="com.wz.dao.CheckItemDao.findItemByGroupId"/>
    </resultMap>

    <!--Front end, cascading query check group-->
    <select id="findCheckGroupAndItemByGroupId" resultMap="getGroup">
      SELECT * FROM t_checkgroup WHERE id IN (SELECT checkgroup_id FROM t_setmeal_checkgroup WHERE setmeal_id =#{id})
    </select>


</mapper>

5. dao of inspection items

Analysis: 1 Called by the upper layer, enter the findItemByGroupId method to start querying the information of each inspection item.

The query results are encapsulated in the CheckItem of their own resultType. Because the upper layer is a list collection, it will become an element access

​ 2. So far, the query is completed, and the multi json nested structure of the page model is realized

	setmeal:{
                img:"",
                name:"",
                checkGroups:[
                    {
                        name:"",
                        code:"",
                        checkItems:[
                            {name:"",code:""}
                        ]
                    }
                ]
            }
<!--Front end, cascading query check items-->
<select id="findItemByGroupId" resultType="CheckItem">
  SELECT * FROM t_checkitem WHERE id IN (SELECT checkitem_id FROM t_checkgroup_checkitem WHERE checkgroup_id=#{id})
</select>

SMS sending

	Alibaba cloud SMS service

	==Watch code implementation==

FreeMarker static page

Official website: http://freemarker.foofun.cn/ Query help documents

Function: make the web page respond faster. After adding, deleting and modifying, generate a static page and call it directly later

Definition: template engine developed by java language

Scenario: page static generation (the process of generating a page loaded with dynamic data into html is called static)

Such as contract template and email template

Composition: template basic template

Data required for model template

Introductory case

1. Guide Package

<!--FreeMarker-->
<dependency>
    <groupId>org.freemarker</groupId>
    <artifactId>freemarker</artifactId>
    <version>2.3.30</version>
</dependencml

​ 2. Prepare the template (the template file should end in. ftl)

<html>
<head>
  <title>Welcome!</title>
</head>
<body>
  <h1>Welcome ${user}!</h1>
  <p>Our latest product:
  
  <#--I'm a comment -- >
   <h1>GOAWAY ${user}!</h1>
  <a href="${latestProduct.url}">${latestProduct.name}</a>!
</body>
</html>

3. Code

It is placed on disk d here. Normally, it is placed under the ftl file of the web

//      Configuration cfg = new Configuration(Configuration.VERSION_2_3_22);
        Configuration cfg = new Configuration(Configuration.getVersion()); //Create freemaker object

        cfg.setDirectoryForTemplateLoading(new File("D:\\te"));//Specify template location

        cfg.setDefaultEncoding("UTF-8"); //Specifies the encoding of the generated template

        Template temp = cfg.getTemplate("ts.ftl"); //Specify the template file name

        //Templates can only be received in json format
        //Create map1
        Map root = new HashMap();
        root.put("user", "Blank");

        //Because there is object data in the template, it is stored in the object
        
        //Mode 1:
        Map latest = new HashMap();
        root.put("latestProduct", latest);
        latest.put("url", "https://www.baidu.com");
        latest.put("name", "Baidu");

        //Mode 2:
        root.put("latestProduct",new User("https://www.baidu.com "," Baidu once ");

        // Through a file output stream, you can write to the corresponding file. Here, the absolute path is used
        FileWriter out = new FileWriter("D:\\te\\test.html");

        temp.process(root, out); //Generate test HTML file

        out.close();  //Turn off the flow, otherwise it will cause memory leakage

FreeMarker instruction

All instructions begin with #

  • assign

    • Define a variable in the template page
    • Use: used when debugging the template. You can define objects or strings. The priority is higher than the variable data passed in from the back end
<html>
<head>
  <title>Welcome!</title>
</head>
<body>
  <h1>Welcome ${user}!</h1>
    
    <!-- Defining variables using instructions -->
    <#assign shit = "Daniel" >
   <h1>GOAWAY ${shit}!</h1>
  <#Assign info = {"mobile": "13812345678", "address": "Changping District, Beijing"} >
 	Telephone: ${info.mobile} Address: ${info.address}
        
  <p>Our latest prodct:
  <#--I'm a comment -- >
  <a href="${latestProduct.url}">${latestProduct.name}</a>!
</body>
</html>
  • include

    • Include other template files and enter the main template file
    • Use: set the path of the template in java and start to find the template files of other paths, which are included in the main template
<html>
<head>
  <title>Welcome!</title>
</head>
<body>
  <h1>Welcome ${user}!</h1>
    <#assign shit = "Daniel" >
   <h1>GOAWAY ${shit}!</h1>
   
   <!-- stay java The location of the file specified in the code is to find the file. And load its contents -->
	<#include "he.ftl">  
</body>
</html>
  • if

    • To judge the conditions, you can define variables in Java or assign.

    • Usage: you can use if else else else if / if to define the key of the map of the passed judgment value in java

      <html>
      <head>
        <title>Welcome!</title>
      </head>
      <body>	
             
         <!-- this success stay Map If there is no definition, an error will be reported -->
         <!-- Exist at the same time to assign Subject to -->
      	<#if success=1>
      		Condition 1 holds..
      	<#elseif success=2>
      		Condition 2 holds..
      	<#else>
      		The condition is not tenable..
      	</#if>
      </body>
      </html>
      
  • list

    • To traverse the collection, java needs to use the list collection to store the map
    • list else execute else if list is empty
    • list ... as ...
   HashMap<Object, Object> map = new HashMap<>();

        //Templates can only be received in json format
        ArrayList<Map> goods = new ArrayList<>();
        
        Map root1 = new HashMap();
        root1.put("name","sa");
        root1.put("price","23");

        Map root2 = new HashMap();
        root2.put("name","sa");
        root2.put("price","23");

        Map root3 = new HashMap();
        root3.put("name","sa");
        root3.put("price","23");

        //Deposit
        goods.add(root1);
        goods.add(root2);
        goods.add(root3);

        map.put("goods",goods);
        // Through a file output stream, you can write to the corresponding file. Here, the absolute path is used
        FileWriter out = new FileWriter("D:\\te\\test.html");
        temp.process(map, out);

The output format of ftl file list takes as as to traverse each

<#list goods as good>
Trade name: ${good.name} Price: ${good.price}<br>
</#list>
  • Built in function

    • Only the date is queried in the official document of the sample here
    • Use after variable when using? Function name
<html>
<head>
  <title>Welcome!</title>
</head>
<body> 
date: Only the date part, not the time part of the day.
time: Only the time part of the day, no date part.
datetime: The date and time are

${openingTime?time}<br>
${openingTime?date}<br>
${openingTime?datetime}<br>
    
//result
22:17:37   
2020-8-10
2020-8-10 22:17:37
    
</body>
</html>

Generate static pages

Timing: generate a static page when any ontology or sub item changes. The static page is generated directly from the code background without asynchronous call!

matters needing attention:

​ 1. Specify the template storage location for the output

​ 2. The automatic injection object in the code is FreeMarkerConfigurer

@Autowired
private FreeMarkerConfigurer freeMarkerConfigurer;//Inject freemaker mapping factory

​ 3. The access address in the template should be consistent with the address in the code. And is the absolute path of the specified disk

​ 4. The generated master page information files are generated in the back-end code and processed logically in the front-end. For example, jump to the page, etc

​ 5. The template shall be in End of ftl

​ 6. Definition of each parameter

    //Define in spring and inject FreeMarkerConfigurer into the code
	 Configuration configuration = freeMarkerConfigurer.getConfiguration();

	cfg.setDirectoryForTemplateLoading(new File("D:\\te"));//Specify template location

    cfg.setDefaultEncoding("UTF-8"); //The converted page coding format is defined in spring

    Template temp = cfg.getTemplate("ts.ftl"); //Which ftl template file in the specified template location is defined in java

    //It is defined in java and spliced with the string of external configuration file
    FileWriter out = new FileWriter("Output path+File name+.html");

    temp.process(map data, out); //Defined in java, the incoming data is generated to the specified location

Steps:

1. Guide Package (latest version here)

<!--FreeMarker-->
<dependency>
    <groupId>org.freemarker</groupId>
    <artifactId>freemarker</artifactId>
    <version>2.3.30</version>
</dependencml

2. Generate package template

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <!-- The above three meta label*must*Put it at the top, anything else*must*Follow! -->
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0,user-scalable=no,minimal-ui">
    <meta name="description" content="">
    <meta name="author" content="">
    <link rel="icon" href="../img/asset-favico.ico">
    <title>make an appointment</title>
    <link rel="stylesheet" href="../css/page-health-order.css" />
</head>
<body data-spy="scroll" data-target="#myNavbar" data-offset="150">
<div class="app" id="app">
    <!-- Page header -->
    <div class="top-header">
        <span class="f-left"><i class="icon-back" onclick="history.go(-1)"></i></span>
        <span class="center">Intellectual health</span>
        <span class="f-right"><i class="icon-more"></i></span>
    </div>
    <!-- Page content -->
    <div class="contentBox">
        <div class="list-column1">
            <ul class="list">
                <li class="list-item">
                    <#--Loop set -- >
                    <#list setmealList as setmeal>
                        <#--Click the link to jump to the inspection group details page -- >
                    <a class="link-page" href="/yemian/setmeal_detail_${setmeal.id}.html?id=${setmeal.id}">
                    <#--<a class="link-page" href="/yemian/setmeal_detail_${setmeal.id}.html">-->
                    <img class="img-object f-left" src="http://qekirsm87.bkt.clouddn.com/${setmeal.img}" alt="">
                    <div class="item-body">
                        <h4 class="ellipsis item-title">${setmeal.name}</h4>
                        <p class="ellipsis-more item-desc">${setmeal.remark}</p>
                        <p class="item-keywords">
                             <span>
                                        <#if setmeal.sex == '0'>
                                            Unlimited gender
                                        <#else>
                                            <#if setmeal.sex == '1'>
                                                male
                                            <#else>
                                                female
                                            </#if>
                                        </#if>
                             </span>
                             <span>${setmeal.age}</span>
                        </p>
                    </div>
                    </a>
                </#list>
                </li>
            </ul>
        </div>
    </div>
</div>
<script>
    var vue = new Vue({
        el:'#app',
        data:{
            setmealList:[]
        }
    });
</body>

3. Generate inspection group template

1.json format return (recommended)

The fastjson dependency package used here. Not recommended

Modified to freemaker syntax, vue is automatically bound to the page in both directions, and the memory consumption is small!!

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <!-- The above three meta label*must*Put it at the top, anything else*must*Follow! -->
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0,user-scalable=no,minimal-ui">
    <meta name="description" content="">
    <meta name="author" content="">
    <link rel="icon" href="../img/asset-favico.ico">
    <title>Appointment details</title>
    <link rel="stylesheet" href="../css/page-health-orderDetail.css" />
    <script src="../plugins/vue/vue.js"></script>
    <script src="../plugins/vue/axios-0.18.0.js"></script>
    <script src="../plugins/healthmobile.js"></script>

    <script>
        var id = getUrlParam("id");
    </script>

</head>
<body data-spy="scroll" data-target="#myNavbar" data-offset="150">
<div id="app" class="app">
    <!-- Page header -->
    <div class="top-header">
        <span class="f-left"><i class="icon-back" onclick="history.go(-1)"></i></span>
        <span class="center">Intellectual health</span>
        <span class="f-right"><i class="icon-more"></i></span>
    </div>
    <!-- Page content -->
    <div class="contentBox">
        <div class="card">
            <div class="project-img">
                <img :src="imgUrl" width="100%" height="100%" />
            </div>
            <div class="project-text">
                <h4 class="tit">{{setmeal.name}}</h4>
                <p class="subtit">{{setmeal.remark}}</p>
                <p class="keywords">
                    <span>{{setmeal.sex == '0' ? 'Unlimited gender' : setmeal.sex == '1' ? 'male':'female'}}</span>
                    <span>{{setmeal.age}}</span>
                </p>
            </div>
            <!--<div class="project-know">
                <a href="orderNotice.html" class="link-page">
                    <i class="icon-ask-circle"><span class="path1"></span><span class="path2"></span></i>
                    <span class="word">Booking instructions</span>
                    <span class="arrow"><i class="icon-rit-arrow"></i></span>
                </a>
            </div>-->
        </div>
        <div class="table-listbox">
            <div class="box-title">
                <i class="icon-zhen"><span class="path1"></span><span class="path2"></span></i>
                <span>Package details</span>
            </div>
            <div class="box-table">
                <div class="table-title">
                    <div class="tit-item flex2">entry name</div>
                    <div class="tit-item  flex3">Project content</div>
                    <div class="tit-item  flex3">Project interpretation</div>
                </div>
                <div class="table-content">
                    <ul class="table-list">
                        <li class="table-item" v-for="checkgroup in setmeal.checkGroups">
                            <div class="item flex2">{{checkgroup.name}}</div>
                            <div class="item flex3">
                                <label v-for="checkitem in checkgroup.checkItems">
                                    {{checkitem.name}}
                                </label>
                            </div>
                            <div class="item flex3">{{checkgroup.remark}}</div>
                        </li>
                    </ul>
                </div>
                <div class="box-button">
                    <a @click="toOrderInfo()" class="order-btn">Make an appointment now</a>
                </div>
            </div>
        </div>
    </div>
</div>
<script>
    var vue = new Vue({
        el:'#app',
        data:{
            imgUrl:null,//Picture link corresponding to the package
    
    //When using json format to send back, you only need to modify it to freemaker syntax here. vue is automatically bound to the page in both directions, and the memory consumption is small!!
            setmeal:${key}   	
        },
        methods:{
            toOrderInfo(){
                window.location.href = "/pages/orderInfo.html?id=" + id;
            }
        },
    });
</script>
</body>
2. Regular return

(placeholders use freemaker syntax)

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <!-- The above three meta label*must*Put it at the top, anything else*must*Follow! -->
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0,user-scalable=no,minimal-ui">
    <meta name="description" content="">
    <meta name="author" content="">
    <link rel="icon" href="../img/asset-favico.ico">
    <title>Appointment details</title>
    <link rel="stylesheet" href="../css/page-health-orderDetail.css" />
    <script src="../plugins/vue/vue.js"></script>
    <script src="../plugins/vue/axios-0.18.0.js"></script>
    <script src="../plugins/healthmobile.js"></script>
    <script>
        var id = getUrlParam("id");
    </script>
</head>
<body data-spy="scroll" data-target="#myNavbar" data-offset="150">
<div id="app" class="app">
    <!-- Page header -->
    <div class="top-header">
        <span class="f-left"><i class="icon-back" onclick="history.go(-1)"></i></span>
        <span class="center">Intellectual health</span>
        <span class="f-right"><i class="icon-more"></i></span>
    </div>
    <!-- Page content -->
    <div class="contentBox">
        <div class="card">
            <div class="project-img">
                <img :src="imgUrl" width="100%" height="100%" />
            </div>
            <div class="project-text">
                <h4 class="tit">${setmeal.name}</h4>
                <p class="subtit">${setmeal.remark}</p>
                <p class="keywords">
                    <span>
						<#if setmeal.sex == '0'>
							Unlimited gender
                        <#else>
                            <#if setmeal.sex == '1'>
								male
                            <#else>
								female
                            </#if>
                        </#if>
                    </span>
                    <span>${setmeal.age}</span>
                </p>
            </div>

        </div>
        <div class="table-listbox">
            <div class="box-title">
                <i class="icon-zhen"><span class="path1"></span><span class="path2"></span></i>
                <span>Package details</span>
            </div>
            <div class="box-table">
                <div class="table-title">
                    <div class="tit-item flex2">entry name</div>
                    <div class="tit-item  flex3">Project content</div>
                    <div class="tit-item  flex3">Project interpretation</div>
                </div>
                <div class="table-content">
                    <ul class="table-list">
                        <#list setmeal.checkGroups as checkgroup>
                             <li class="table-item">
                                 <div class="item flex2">${checkgroup.name}</div>
                                    <div class="item flex3">
                                              <#list checkgroup.checkItems as checkitem>
                                                   <label>
                                                      ${checkitem.name}
                                                   </label>
                                              </#list>
                                    </div>
                                 <div class="item flex3">${checkgroup.remark}</div>
                            </li>
                        </#list>
                    </ul>
                </div>
                <div class="box-button">
                    <a @click="toOrderInfo()" class="order-btn">Make an appointment now</a>
                </div>
            </div>
        </div>
    </div>
</div>
<script>
    var vue = new Vue({
        el:'#app',
        data:{
            imgUrl:null,//Picture link corresponding to the package
            setmeal:{}
        },
        methods:{
            toOrderInfo(){
                window.location.href = "/pages/orderInfo.html?id=" + id;
            }
     }
    });
</script>
</body>

4. Tools

Function: after the addition, deletion and modification operations are completed, the method is directly executed, and the internal method is queried to generate a template. The front end automatically accesses the template.

 //Generate template method
    public void makeTemplate(String templateFileName, String pageName, Map data) throws Exception {
        //Get objects through factory
        Configuration configuration = freeMarkerConfigurer.getConfiguration();

        //Specify template
        Template template = configuration.getTemplate(templateFileName);

        //Create output stream
        FileWriter fileWriter = new FileWriter(new File(outputpath+"/"+pageName));

        //Output template
        template.process(data,fileWriter);

        //Closed flow
        fileWriter.close();
    }

-----------------------------Detailed page---------------------------------------------------------------------
-----------------------------Detailed page---------------------------------------------------------------------
-----------------------------Detailed page---------------------------------------------------------------------
 //Method of generating detailed page
    public void makeStaticDetailPage(List<Setmeal> list) throws Exception {

        //Define template name
//      String templateName = "setmeal_detail.ftl";
        String templateName = "setmeal_detailForSmall.ftl"; //Template returned using map

        //Cyclic set
        for(Setmeal setmeal : list){

            //Define the generated file name, and the end of the file ends according to the package id. It is convenient for the front-end to find out when using the cycle
            String detailPageName = "setmeal_detail_"+String.valueOf(setmeal.getId()+".html");

           //Cascade query all subsets to obtain results
           List<Setmeal> s = mealDao.getCheckGroupsAndCheckItemsInMeal(String.valueOf(setmeal.getId()));

            //Get the queried package object
            Setmeal smeal = s.get(0);

           //Create map
            HashMap<String, String> map = new HashMap<>();
            String s1 = JSON.toJSONString(smeal);
            //Save to collection
//          map.put("setmeal",smeal);
            map.put("key",s1); //When using the template of map. Return json format

            //Call basic template method to generate static page
            makeTemplate(templateName,detailPageName,map);

        }
    
    
-----------------------------Package page---------------------------------------------------------------------
-----------------------------Package page---------------------------------------------------------------------
-----------------------------Package page---------------------------------------------------------------------
    //Method of generating package page
    //Generate the package page, throw up the exception, and the one who calls will handle it
    public void makeStaticPage(List<Setmeal> list) throws Exception {

        //Define data
        HashMap<String, List<Setmeal>> map = new HashMap<>();

        //Save to map
        map.put("setmealList",list);

        //Define template name
        String templateName = "m.ftl";

        //Define the generated file name
        String mealPageName = "mealPage.html";

        //Call the basic template method to generate a web page and output it to the specified location
        makeTemplate(templateName,mealPageName,map);
    }
    

5. Configuration file

​ 1. Configure freemarkerConfig in the spring container in the business layer

<!--to configure freemarker Template object-->
<bean id="freemarkerConfig" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
        <!--Specify the directory where the template file is located, which cannot be accessed externally-->
        <property name="templateLoaderPath" value="/WEB-INF/ftl/" />
        <!--Specify character set-->
        <property name="defaultEncoding" value="UTF-8" />
</bean>

​ 2. Create external file for address

outputPath=F:/ideaProject/project/projectHEALTH/mobile/src/main/webapp/yemian //Absolute path of webapp on disk in the project

6. Modify the initial access interface

In the index, modify the first jump position as the template page

Confirm appointment

datepicker date control Android

The back-end of ID card verification is the ID card obtained by the server connected to the Public Security Bureau? The ID card has a set of verification rules

Why can't the pre submission verification here be handed over to vue? The number of verification backend visitors is small

How can the front-end page verify the regularity on the basis of losing focus? async-validator

Provide a general query condition to return the list set and template

<!--Dynamic condition query-->
<select id="findByCondition" parameterType="com.itheima.pojo.Order" resultMap="baseResultMap">
    select * from t_order
    <where>
        <if test="id != null">
            and id = #{id}
        </if>
        <if test="memberId != null">
            and member_id = #{memberId}
        </if>
        <if test="orderDate != null">
            and orderDate = #{orderDate}
        </if>
        <if test="orderType != null">
            and orderType = #{orderType}
        </if>
        <if test="orderStatus != null">
            and orderStatus = #{orderStatus}
        </if>
        <if test="setmealId != null">
            and setmeal_id = #{setmealId}
        </if>
    </where>
</select>

Authority control (RBAC)

Why should the cookie be set to / so that not all paths will carry the cookie? General operation all pages need to be verified

The interception rule / * * intercepts all requests, which is unique to the / * security framework previously used

Using annotations, after authentication, this can access other methods. Is it defined in memory using the value string

Configure the form and loginout tags. What if there are other customized pages to be released?

<security:http security="none" pattern="/pages/a.html"></security:http>

How to jump to the service page from spring

<security:authentication-provider  user-service-ref="logical">

The spring security framework supports the following functions:

Login: automatically generate login URL for entering password account.

Authentication: the bottom layer of the framework automatically connects with the results of the specified method through the secret code website.

Authentication: judge the permission according to the given method

Exit: the bottom layer of the framework automatically logs off all permission functions through the password URL

site: spring.io keyword query according to the keyword of the website

matters needing attention

​ 1.access and exception should be consistent

​ 2. When configuring users, {noop} of password indicates whether to configure the plaintext

​ 3. Using the form tag, the form submission must be post, otherwise 404

​ 4. If you encounter ifram nested web pages, it is considered unsafe. You need to configure the security: header tag in the http tag

Project definition: war package, not inheriting the parent project

In the web

/Do not intercept JSPS

/No interception*

*. do intercept only Do end request

step

pom.xml

1. Import dependent packages

In general, we need to rely on spring, which is not given here

<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-config</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-taglibs</artifactId>
</dependency>

web.xml

2. Configure delegatingFilterproxy delegation filter

delegatingFilterproxy class function: integrate the tripartite framework, including shrio

<!DOCTYPE web-app PUBLIC
        "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
        "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>Archetype Created Web Application</display-name>
  <filter>
    <!--
      DelegatingFilterProxy Used to integrate third-party frameworks
      integration Spring Security The name of the filter must be springSecurityFilterChain,
	  Otherwise, it will be thrown NoSuchBeanDefinitionException abnormal
    -->
    <filter-name>springSecurityFilterChain</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
  </filter>

  <filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>

  <servlet>
    <servlet-name>springmvc</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <!-- Specify the loaded configuration file through parameters contextConfigLocation load -->
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:spring.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>

  <servlet-mapping>
    <servlet-name>springmvc</servlet-name>
    <url-pattern>/*</url-pattern>
  </servlet-mapping>
</web-app>

spring.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:security="http://www.springframework.org/schema/security"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/mvc
       http://www.springframework.org/schema/mvc/spring-mvc.xsd
       http://code.alibabatech.com/schema/dubbo
       http://code.alibabatech.com/schema/dubbo/dubbo.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/security
       http://www.springframework.org/schema/security/spring-security.xsd

">

    <!--Sweep bag-->
    <context:component-scan base-package="com.wz"/>

    <!--Release static page-->
    <mvc:default-servlet-handler/>

    <!--scanning spring Annotation of framework-->
    <mvc:annotation-driven/>



    <!-- Configure layer 2 interceptor -->
        <!--1.Configure addresses that can be accessed directly-->
        <!--<security:http security="none" pattern="/pages/a.html"></security:http>-->

        <!--2.Configure the address to be intercepted-->
        <!--Due to permission verification, if not, it will automatically jump to the framework login page-->
        <security:http auto-config="true" use-expressions="true">
               <!-- This role is required to access the following web pages -->
              <security:intercept-url pattern="/user/**" access="hasRole('ROLE_ADMIN')" />
              <security:intercept-url pattern="/TT/**" access="hasRole('ROLE_GOOD')" />
              <security:intercept-url pattern="/pages/**" access="isAuthenticated()" />
                <!--Anonymous Access -->
              <!--<security:intercept-url pattern="/pages/**" access="isAnonymous()" />-->

            <!--Custom login page-->
            <!--Because the custom page is set, you need to use the interceptor caller to authorize-->
            <security:form-login
                    login-page="/login.html"
                    username-parameter="account"
                    password-parameter="password"
                    login-processing-url="/hhhh"
                    default-target-url="/index.html"
                    authentication-failure-url="/login.html"></security:form-login>

            <!--Turn off the filter of the custom form, and all requests will be intercepted-->
            <security:csrf disabled="true"></security:csrf>

            <!--Log out and log out all permission information-->
            <security:logout logout-url="/logout"
                             logout-success-url="/login.html"
                             invalidate-session="true"
            />
            </security:http>

    <!--Configure layer 3 interceptors, which are mainly used for logical control and allocation of permissions-->
        <security:authentication-manager>
            <!-- Define interceptor caller -->
            <!--<security:authentication-provider  user-service-ref="logical">-->
            <security:authentication-provider >

            <!-- Configure a specific user data write dead, as long as it meets name,pwd Just give me permission -->
            <security:user-service>
                <!--{noop}Indicates that plaintext is used-->
                <security:user name="admin1" password="{noop}123" authorities="ROLE_ADMIN"/>
            </security:user-service>

                <!--Specify the object to be encrypted with password, and the underlying layer will encrypt it by itself-->
                <!--Carry out password verification in the password address. If the password is correct, give permission-->
                <!--<security:password-encoder ref="passwordEncoder"></security:password-encoder>-->

            </security:authentication-provider>

        </security:authentication-manager>

    <!--Enable annotation mode permission control-->
    <security:global-method-security pre-post-annotations="enabled" />

    <!-- definition bean,For logical allocation -->
        <bean id="logical" class="com.wz.LogicalService"></bean>

    <!--Configure password encryption object-->
        <bean id="passwordEncoder"
              class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"
        />


    <!--<dubbo:application name="dubbo_controller" />-->
    <!--&lt;!&ndash;Specify service registry address&ndash;&gt;-->
    <!--<dubbo:registry address="zookeeper://localhost:2181"/>-->
    <!--&lt;!&ndash;Batch scan&ndash;&gt;-->
    <!--<dubbo:annotation package="com.wz" />-->
</beans>

Rectification of Project Authority

The annotation here can only use one permission. How to write if you want multiple permissions? json cannot use and to connect multiple permissions

1. Jointly query all permissions to reduce the performance consumption of the database. Otherwise, the more permissions and roles, the more queries to access the database. If you combine queries, you can query all of them only once

Optimization scheme:

​ 1. The mian page is optimized to display the user's name

​ 2. The corresponding permission operation button is displayed. If there is a deletion, it will be displayed

​ 3. If the deletion fails, a prompt will be given, and the permission is insufficient (choose one of 2 / 3)

File export

Upgrade self-study poi: easypoi toolkit, easy excel, Alibaba's poi performance optimization project

Create one object at a time?

Mode 1:

Export a template directly

window.location.href = '/report/BusinessReport.xlsx';  //Export template files stored in a region of the server

Mode 2:

ajax is not used here, because if it is used, the stream needs to be encapsulated as sjon return

Access the background, generate data, and then export it by stream

package com.wz.analysis;

import com.alibaba.dubbo.config.annotation.Reference;
import com.interfaces.Analysis;

import com.wz.result.MessageConstant;
import com.wz.result.Result;
import org.apache.poi.xssf.usermodel.*;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@RestController
@RequestMapping("/report")
public class MemberAnalysis {

    @Reference
    private Analysis analysis;

    //Call the method to get the new number of people per month in the past year
    @RequestMapping("/showMemberReport")
    public Map showMemberReport(){

        Map map = analysis.checkMemberCountByMonths();

        return map;
    }


    //Call the method to get the new number of people per month in the past year
    @RequestMapping("/showMealReport")
    public Map showMealReport(){
        //Call the method to get the reservation quantity of each package
         Map map = analysis.checkMealReservation();
         return map;
    }

    //Call method to get report data
    @RequestMapping("/showReport")
    public Result showReport(){
        try{
            Map<String,Object> data = analysis.checkReportInfo();
            return new Result(true,MessageConstant.GET_BUSINESS_REPORT_SUCCESS,data);
        }catch (Exception e){
            return new Result(false,MessageConstant.GET_BUSINESS_REPORT_FAIL);
        }
    }


    //export report
    @RequestMapping("/exportBusinessReport")
    public Result exportBusinessReport(HttpServletRequest request, HttpServletResponse response) throws Exception {

        try {
            //Read in template file
            String filePath = request.getSession().getServletContext().getRealPath("template") + File.separator + "report_template.xlsx";

            //Get file workbook object
            XSSFWorkbook excel = new XSSFWorkbook(new FileInputStream(new File(filePath)));

            //

            //get data
            Map<String, Object> result = analysis.checkReportInfo();
            //Take out the returned result data and prepare to write the report data into Excel file
            String reportDate = (String) result.get("reportDate");
            Integer todayNewMember = (Integer) result.get("todayNewMember");
            Integer totalMember = (Integer) result.get("totalMember");
            Integer thisWeekNewMember = (Integer) result.get("thisWeekNewMember");
            Integer thisMonthNewMember = (Integer) result.get("thisMonthNewMember");
            Integer todayOrderNumber = (Integer) result.get("todayOrderNumber");
            Integer thisWeekOrderNumber = (Integer) result.get("thisWeekOrderNumber");
            Integer thisMonthOrderNumber = (Integer) result.get("thisMonthOrderNumber");
            Integer todayVisitsNumber = (Integer) result.get("todayVisitsNumber");
            Integer thisWeekVisitsNumber = (Integer) result.get("thisWeekVisitsNumber");
            Integer thisMonthVisitsNumber = (Integer) result.get("thisMonthVisitsNumber");
            List<Map> hotSetmeal = (List<Map>) result.get("hotSetmeal");

            //
            XSSFSheet sheet = excel.getSheetAt(0);
            // Get how many rows and columns are public
            int rowNum = sheet.getLastRowNum();  //Get all rows
            for (int i = 0; i <=rowNum ; i++) {
                XSSFRow row = sheet.getRow(i);  //Get single line object
                if(row!=null){
                    int colNum = row.getLastCellNum();  //Gets the last cell of the row. Contains used cells
                    for (int j = 0; j < colNum; j++) {
                        XSSFCell cell = row.getCell(j);   //Get each cell object
                        if(cell!=null){
                            XSSFCellStyle cellStyle = cell.getCellStyle();  //Get style object
                            // The red background is FFFF0000
                            // The green background is FF00B050
                            if(cellStyle.getFillForegroundColorColor()!=null) {  //Judge whether there is color
                                String color = cellStyle.getFillForegroundColorColor().getARGBHex(); //Get color number
                                System.out.println(cell.getStringCellValue()+"\t:"+color+"\t"+result.get(cell.getStringCellValue()));

                                if("FFFF0000".equals(color)||"FFFFFF00".equals(color)){  //Judge whether it is the specified color. The color here is bright red and green
                                    String [] name = cell.getStringCellValue().split(":");   //Split the cells to determine whether the hot plate has been reached
                                    cellStyle.setFillForegroundColor(new XSSFColor(Color.YELLOW)); //Fill new style
                                    if(name.length==2) {//Judge whether the split result really reaches the hot plate
                                        Map map = (Map) result.get(name[0]); //Sethotkey here, sethotkey here
                                        cell.setCellValue("" + map.get(name[1])); //value
                                    }else{
                                        //The value of each cell to be filled in the template is the key of the result query result
                                        cell.setCellValue("" + result.get(cell.getStringCellValue()));
                                    }
                                }
                            }
                        }
                    }
                }
            }


            //Use the output stream to download the form, and download it as a client based on the browser
            OutputStream out = response.getOutputStream();
            response.setContentType("application/vnd.ms-excel");//Represents the Excel file type
            response.setHeader("content-Disposition", "attachment;filename=report.xlsx");//Specify download as attachment
            excel.write(out);

            out.flush();
            out.close();
//            excel.close();
            return null;
        }catch (Exception e){
            e.printStackTrace();
            return new Result(false,MessageConstant.GET_SETMEAL_COUNT_REPORT_FAIL);
        }
    }
}

JasperReport simulation Designer

Note: 1 When using the form, the data source is specified, so the data can be displayed

However, if it is executed in the program, there is no way to close it. There will be problems, so don't

​ 2. When generating the border, in order to have no gap. To zoom out each area, the lower line of the previous area

​ 3. If Chinese cannot be displayed normally, use Chinese Song typeface and add pudding file at the same level as jrxml template

Try not to use the fields function to make reports in the future?

Output stream ateBytes. tostring

XX.class. -->

getResource ("") takes the files under the same package

getResource ("/") takes the file under the class file

getClassLoader.getResource(" ")

getClassLoader.getResource(" /")

Introductory case

    @Test
    public void show() throws Exception {
        //Define template location
         String jrxmlPath ="F:\\ideaProject\\project\\projectHEALTH\\controller\\src\\main\\resources\\demo.jrxml";
        
        //Define virtual output location and name
         String jasperPath ="F:\\ideaProject\\project\\projectHEALTH\\controller\\src\\main\\resources\\demo.jasper";

         JasperCompileManager.compileReportToFile(jrxmlPath,jasperPath);  //Compile template
        
        //Define header data
         Map paramters = new HashMap();
         paramters.put("reportDate","2019-10-10");
         paramters.put("company","itcast");

        //Define template master data
         List<Map> list = new ArrayList();
         HashMap<Object, Object> map1 = new HashMap<>();
         map1.put("name","xiaoming");
         map1.put("address","beijing");
         map1.put("email","xiaoming@itcast.cn");
         Map map2 = new HashMap();
         map2.put("name","xiaoli");
         map2.put("address","nanjing");
         map2.put("email","xiaoli@itcast.cn");
         list.add(map1);
         list.add(map2);
        
         //Fill in the data and use the javaBean class   
         JasperPrint jasperPrint =JasperFillManager.fillReport(jasperPath,paramters,new JRBeanCollectionDataSource(list));
        
         //Define output file location
         String pdfPath = "D:\\test.pdf";
         JasperExportManager.exportReportToPdfFile(jasperPrint,pdfPath); //export

  }
}

Color.YELLOW)); // Fill new style
if(name.length==2) {/ / judge whether the split result really reaches the popular plate
Map map = (Map) result. get(name[0]); // Sethotkey here, sethotkey here
cell.setCellValue("" + map.get(name[1])); //value
}else{
//The value of each cell to be filled in the template is the key of the result query result
cell.setCellValue("" + result.get(cell.getStringCellValue()));
}
}
}
}
}
}
}

        //Use the output stream to download the form, and download it as a client based on the browser
        OutputStream out = response.getOutputStream();
        response.setContentType("application/vnd.ms-excel");//Represents the Excel file type
        response.setHeader("content-Disposition", "attachment;filename=report.xlsx");//Specify download as attachment
        excel.write(out);

        out.flush();
        out.close();

// excel.close();
return null;
}catch (Exception e){
e.printStackTrace();
return new Result(false,MessageConstant.GET_SETMEAL_COUNT_REPORT_FAIL);
}
}
}





## JasperReport simulation Designer

​		Note: 1.When using the form, the data source is specified, so the data can be displayed

​					However, if it is executed in the program, there is no way to close it. There will be problems, so don't

​					2.When generating the border, in order to have no gap. To zoom out each area, the lower line of the previous area

​					3.If Chinese cannot be displayed normally, use Chinese Song typeface and add pudding files and jrxml Template sibling

==Try not to use it in the future feilds Function: create report?==

Output stream ateBytes . tostring

XX.class. -->

getResource(" ") Take the same package and put down the documents

getResource("/ ")take class File under file

getClassLoader.getResource(" ")

getClassLoader.getResource(" /")



Introductory case

```java
    @Test
    public void show() throws Exception {
        //Define template location
         String jrxmlPath ="F:\\ideaProject\\project\\projectHEALTH\\controller\\src\\main\\resources\\demo.jrxml";
        
        //Define virtual output location and name
         String jasperPath ="F:\\ideaProject\\project\\projectHEALTH\\controller\\src\\main\\resources\\demo.jasper";

         JasperCompileManager.compileReportToFile(jrxmlPath,jasperPath);  //Compile template
        
        //Define header data
         Map paramters = new HashMap();
         paramters.put("reportDate","2019-10-10");
         paramters.put("company","itcast");

        //Define template master data
         List<Map> list = new ArrayList();
         HashMap<Object, Object> map1 = new HashMap<>();
         map1.put("name","xiaoming");
         map1.put("address","beijing");
         map1.put("email","xiaoming@itcast.cn");
         Map map2 = new HashMap();
         map2.put("name","xiaoli");
         map2.put("address","nanjing");
         map2.put("email","xiaoli@itcast.cn");
         list.add(map1);
         list.add(map2);
        
         //Fill in the data and use the javaBean class   
         JasperPrint jasperPrint =JasperFillManager.fillReport(jasperPath,paramters,new JRBeanCollectionDataSource(list));
        
         //Define output file location
         String pdfPath = "D:\\test.pdf";
         JasperExportManager.exportReportToPdfFile(jasperPrint,pdfPath); //export

  }
}

Posted by beselabios on Thu, 12 May 2022 00:19:11 +0300