当前位置:网站首页>Grain Mall - distributed Foundation

Grain Mall - distributed Foundation

2022-06-26 10:51:00 Pig man blogs

1. Overall introduction

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-zFElrYTr-1592811187412)(images/image-20200422211607028.png)]

1) install vagrant

2) install Centos7

$ vagrant init centos/7
A `Vagrantfile` has been placed in this directory. You are now
ready to `vagrant up` your first virtual environment! Please read
the comments in the Vagrantfile as well as documentation on
`vagrantup.com` for more information on using Vagrant.

After executing the above command , Will be generated in the user's home directory Vagrantfile file .

$ vagrant up
Bringing machine 'default' up with 'virtualbox' provider...
==> default: Box 'centos/7' could not be found. Attempting to find and install...
    default: Box Provider: virtualbox
    default: Box Version: >= 0
==> default: Loading metadata for box 'centos/7'
    default: URL: https://vagrantcloud.com/centos/7
==> default: Adding box 'centos/7' (v1905.1) for provider: virtualbox
    default: Downloading: https://vagrantcloud.com/centos/boxes/7/versions/1905.1/providers/virtualbox.box
    default: Download redirected to host: cloud.centos.org
    default: Progress: 0% (Rate: 6717/s, Estimated time remaining: 7:33:42)

Downloading images is a long process , You can also use the download tool to download to the local area first and then , And then use “ vagrant box add ” add to , Again “vagrant up” that will do

# Add the downloaded image to virtualBox in 
$ vagrant box add centos/7 E:\ Thunder download \CentOS-7-x86_64-Vagrant-1905_01.VirtualBox.box
==> box: Box file was not detected as metadata. Adding it directly...
==> box: Adding box 'centos/7' (v0) for provider:
    box: Unpacking necessary files from: file:///E:/%D1%B8%C0%D7%CF%C2%D4%D8/CentOS-7-x86_64-Vagrant-1905_01.VirtualBox.box
    box:
==> box: Successfully added box 'centos/7' (v0) for 'virtualbox'!

# start-up 
$ vagrant up
Bringing machine 'default' up with 'virtualbox' provider...
==> default: Importing base box 'centos/7'...
==> default: Matching MAC address for NAT networking...
==> default: Setting the name of the VM: Administrator_default_1588497928070_24634
==> default: Clearing any previously set network interfaces...
==> default: Preparing network interfaces based on configuration...
    default: Adapter 1: nat
    default: Adapter 2: hostonly
==> default: Forwarding ports...
    default: 22 (guest) => 2222 (host) (adapter 1)
==> default: Booting VM...
==> default: Waiting for machine to boot. This may take a few minutes...
    default: SSH address: 127.0.0.1:2222
    default: SSH username: vagrant
    default: SSH auth method: private key
    default:
    default: Vagrant insecure key detected. Vagrant will automatically replace
    default: this with a newly generated keypair for better security.
    default:
    default: Inserting generated public key within guest...
    default: Removing insecure key from the guest if it's present...
    default: Key inserted! Disconnecting and reconnecting using new SSH key...
==> default: Machine booted and ready!
==> default: Checking for guest additions in VM...
    default: No guest additions were detected on the base box for this VM! Guest
    default: additions are required for forwarded ports, shared folders, host only
    default: networking, and more. If SSH fails on this machine, please install
    default: the guest additions and repackage the box to continue.
    default:
    default: This is not an error message; everything may continue to work properly,
    default: in which case you may ignore this message.
==> default: Configuring and enabling network interfaces...
==> default: Rsyncing folder: /cygdrive/c/Users/Administrator/ => /vagrant


vagrant ssh Turn on SSH, And log in to centos7

$ vagrant ssh
[[email protected] ~]$ ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 52:54:00:8a:fe:e6 brd ff:ff:ff:ff:ff:ff
    inet 10.0.2.15/24 brd 10.0.2.255 scope global noprefixroute dynamic eth0
       valid_lft 86091sec preferred_lft 86091sec
    inet6 fe80::5054:ff:fe8a:fee6/64 scope link
       valid_lft forever preferred_lft forever
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 08:00:27:d1:76:f6 brd ff:ff:ff:ff:ff:ff
    inet 192.168.56.102/24 brd 192.168.56.255 scope global noprefixroute dynamic eth1
       valid_lft 892sec preferred_lft 892sec
    inet6 fe80::8c94:1942:ba09:2458/64 scope link noprefixroute
       valid_lft forever preferred_lft forever
[[email protected] ~]$
C:\Users\Administrator>ipconfig

Windows IP  To configure 

 Ethernet adapter  VirtualBox Host-Only Network:

    Connect specific  DNS  suffix  . . . . . . . :
    Local link  IPv6  Address . . . . . . . . : fe80::a00c:1ffa:a39a:c8c2%16
   IPv4  Address  . . . . . . . . . . . . : 192.168.56.1
    Subnet mask   . . . . . . . . . . . . : 255.255.255.0
    The default gateway . . . . . . . . . . . . . :

Configure network information , open "Vagrantfile" file :

config.vm.network "private_network", ip: "192.168.56.10"

After the modification is completed , Restart vagrant

vagrant reload

Check host and virtualBox Whether the communication between is normal

[[email protected] ~]$ ping 192.168.43.43                                                                                                         PING 192.168.43.43 (192.168.43.43) 56(84) bytes of data.
64 bytes from 192.168.43.43: icmp_seq=1 ttl=127 time=0.533 ms
64 bytes from 192.168.43.43: icmp_seq=2 ttl=127 time=0.659 ms

--- 192.168.43.43 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 999ms
rtt min/avg/max/mdev = 0.533/0.596/0.659/0.063 ms
[[email protected] ~]$
[[email protected] ~]$
[[email protected] ~]$ ping www.baidu.com
PING www.a.shifen.com (112.80.248.76) 56(84) bytes of data.
64 bytes from 112.80.248.76 (112.80.248.76): icmp_seq=1 ttl=53 time=56.1 ms
64 bytes from 112.80.248.76 (112.80.248.76): icmp_seq=2 ttl=53 time=58.5 ms
64 bytes from 112.80.248.76 (112.80.248.76): icmp_seq=3 ttl=53 time=53.4 ms

Open remote login , modify “/etc/ssh/sshd_config”

PermitRootLogin yes 
PasswordAuthentication yes

And then restart SSHD

systemctl restart sshd

Use Xshell or SecureCRT Make a remote connection .

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-IDG8FtCs-1592811187419)(images/image-20200503174735162.png)]

2. docker Install in mysql

[[email protected] module]# docker pull mysql:5.7
5.7: Pulling from library/mysql
123275d6e508: Already exists 
27cddf5c7140: Pull complete 
c17d442e14c9: Pull complete 
2eb72ffed068: Pull complete 
d4aa125eb616: Pull complete 
52560afb169c: Pull complete 
68190f37a1d2: Pull complete 
3fd1dc6e2990: Pull complete 
85a79b83df29: Pull complete 
35e0b437fe88: Pull complete 
992f6a10268c: Pull complete 
Digest: sha256:82b72085b2fcff073a6616b84c7c3bcbb36e2d13af838cec11a9ed1d0b183f5e
Status: Downloaded newer image for mysql:5.7
docker.io/library/mysql:5.7

Look at the mirror image

[[email protected] module]# docker images
REPOSITORY  TAG    IMAGE ID     CREATED       SIZE
mysql       5.7    f5829c0eee9e 2 hours ago   455MB
[[email protected] module]# 

start-up mysql

sudo docker run -p 3306:3306 --name mysql \
-v /mydata/mysql/log:/var/log/mysql \
-v /mydata/mysql/data:/var/lib/mysql \
-v /mydata/mysql/conf:/etc/mysql \
-e MYSQL_ROOT_PASSWORD=root \
-d mysql:5.7

Modify the configuration

[[email protected] conf]# pwd
/mydata/mysql/conf


[[email protected] conf]# cat my.cnf
[client]
default-character-set=utf8
[mysql]
default-character-set=utf8
[mysqld]
init_connect='SET collation_connection = utf8_unicode_ci'
init_connect='SET NAMES utf8'
character-set-server=utf8
collation-server=utf8_unicode_ci
skip-character-set-client-handshake
skip-name-resolve
[[email protected] conf]# 

[[email protected] conf]# docker restart mysql
mysql
[[email protected] conf]# 

Go to the container to see the configuration :

[[email protected] conf]# docker exec -it mysql /bin/bash
[email protected]:/# whereis mysql
mysql: /usr/bin/mysql /usr/lib/mysql /etc/mysql /usr/share/mysql

[email protected]:/# ls /etc/mysql 
my.cnf
[email protected]:/# cat /etc/mysql/my.cnf 
[client]
default-character-set=utf8
[mysql]
default-character-set=utf8
[mysqld]
init_connect='SET collation_connection = utf8_unicode_ci'
init_connect='SET NAMES utf8'
character-set-server=utf8
collation-server=utf8_unicode_ci
skip-character-set-client-handshake
skip-name-resolve
[email protected]d7:/# 

Set to start docker when , I.e. operation mysql

[[email protected] ~]# docker update mysql --restart=always
mysql
[[email protected] ~]# 

3. docker Install in redis

download docker

[[email protected] ~]# docker pull redis
Using default tag: latest
latest: Pulling from library/redis
123275d6e508: Already exists 
f2edbd6a658e: Pull complete 
66960bede47c: Pull complete 
79dc0b596c90: Pull complete 
de36df38e0b6: Pull complete 
602cd484ff92: Pull complete 
Digest: sha256:1d0b903e3770c2c3c79961b73a53e963f4fd4b2674c2c4911472e8a054cb5728
Status: Downloaded newer image for redis:latest
docker.io/library/redis:latest

start-up docker

[[email protected] ~]# mkdir -p /mydata/redis/conf
[[email protected] ~]# touch /mydata/redis/conf/redis.conf
[[email protected] ~]# echo "appendonly yes" >> /mydata/redis/conf/redis.conf
[[email protected] ~]# docker run -p 6379:6379 --name redis -v /mydata/redis/data:/data \
> -v /mydata/redis/conf/redis.conf:/etc/redis/redis.conf \
> -d redis redis-server /etc/redis/redis.conf
ce7ae709711986e3f90c9278b284fe6f51f1c1102ba05f3692f0e934ceca1565
[[email protected] ~]# 

Connect to docker Of redis

[[email protected] ~]# docker exec -it redis redis-cli
127.0.0.1:6379> set key1 v1
OK
127.0.0.1:6379> get key1
"v1"
127.0.0.1:6379> 

Set up redis The container in docker It starts when it starts

[[email protected] ~]# docker update redis --restart=always
redis
[[email protected] ~]# 

4. establish maven engineering

5. perform sql Script

gulimall_oms.sql
gulimall_pms.sql
gulimall_sms.sql
gulimall_ums.sql
gulimall_wms.sql
pms_catelog.sql
sys_menus.sql

6. clone Open source for all

https://gitee.com/renrenio

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-dDw7PcTS-1592811187422)(images/1587609877028.png)]

Clone locally :

git clone https://gitee.com/renrenio/renren-fast-vue.git

git clone https://gitee.com/renrenio/renren-fast.git

To be copied “renren-fast” Delete “.git” after , copy to “gulimall” Project root directory , Then use it as gulimall One of the module

establish “gulimall_admin” The database of , And then execute “renren-fast/db/mysql.sql” Medium SQl Script

modify “application-dev.yml” file , The default is dev Environmental Science , Modify connection mysql Of url And username and password

spring:
    datasource:
        type: com.alibaba.druid.pool.DruidDataSource
        druid:
            driver-class-name: com.mysql.cj.jdbc.Driver
            url: jdbc:mysql://192.168.137.14:3306/gulimall_admin?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
            username: root
            password: root

start-up “gulimall_admin”, And then visit “http://localhost:8080/renren-fast/

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-Cm8F2gWa-1592811187428)(images/1587616296253.png)]

install node.js, And install the warehouse

npm config set registry http://registry.npm.taobao.org/
PS D:\tmp\renren-fast-vue> npm config set registry http://registry.npm.taobao.org/
PS D:\tmp\renren-fast-vue> npm install
npm WARN [email protected] requires a peer of [email protected]>=4.10.0 but none is installed. You must install peer dependencies yourself.
npm WARN [email protected] requires a peer of [email protected]^4.0.0 but none is installed. You must install peer dependencies yourself.
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: [email protected] (node_modules\fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for [email protected]: wanted {
    "os":"darwin","arch":"any"} (current: {
    "os":"win32","arch":"x64"})

up to date in 17.227s
PS D:\tmp\renren-fast-vue> 
PS D:\tmp\renren-fast-vue> npm run dev

> [email protected] dev D:\tmp\renren-fast-vue
> webpack-dev-server --inline --progress --config build/webpack.dev.conf.js

 10% building modules 5/10 modules 5 active ...-0!D:\tmp\renren-fast-vue\src\main.js(node:19864) Warning: Accessing non-existent property 'cat' of module exports inside circular dependency
(Use `node --trace-warnings ...` to show where the warning was created)
(node:19864) Warning: Accessing non-existent property 'cd' of module exports inside circular dependency
(node:19864) Warning: Accessing non-existent property 'chmod' of module exports inside circular dependency
(node:19864) Warning: Accessing non-existent property 'cp' of module exports inside circular dependency
(node:19864) Warning: Accessing non-existent property 'dirs' of module exports inside circular dependency
(node:19864) Warning: Accessing non-existent property 'pushd' of module exports inside circular dependency
(node:19864) Warning: Accessing non-existent property 'popd' of module exports inside circular dependency
(node:19864) Warning: Accessing non-existent property 'echo' of module exports inside circular dependency
(node:19864) Warning: Accessing non-existent property 'tempdir' of module exports inside circular dependency
(node:19864) Warning: Accessing non-existent property 'pwd' of module exports inside circular dependency

common problem 1:“Module build failed: Error: Cannot find module 'node-sass”

In operation , appear “Module build failed: Error: Cannot find module 'node-sass’ Report the wrong question ”, resolvent

use npm install -g cnpm --registry=https://registry.npm.taobao.org , Download from Taobao image , then cnpm Download successful .

Last input cnpm install node-sass --save.npm run dev Finally able to run !!!
————————————————
Copyright notice : This paper is about CSDN Blogger 「 The setting sun makes a beautiful silhouette 」 The original article of , follow CC 4.0 BY-SA Copyright agreement , For reprint, please attach the original source link and this statement .
Link to the original text :https://blog.csdn.net/qq_38401285/article/details/86483278

common problem 2:cnpm - solve " cnpm : Unable to load file C:\Users\93457\AppData\Roaming\npm\cnpm.ps1, Because scripts are not allowed to run on this system . For more information ... "

https://www.cnblogs.com/500m/p/11634969.html

The root cause of all the problems lies in “node_modules”,npm install Before , This folder should be deleted , Then install and run .

Run again npm run dev Back to normal :

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-IljLqMJG-1592811187431)(images/1587637858665.png)]

7. clone renren-generator

clone

https://gitee.com/renrenio/renren-generator.git

Then place the item in “gulimall” Following the path of , Then add the Module, And submit it to github On

Modify the configuration

renren-generator/src/main/resources/generator.properties

# Code generator , Configuration information 

mainPath=com.bigdata
# Package name 
package=com.bigdata.gulimall
moduleName=product
# author 
author=cosmoswong
#Email
[email protected]
# Table prefix ( The class name will not contain the table prefix )
tablePrefix=pms_

function “renren-generator”

visit :<http://localhost:80/

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-X98uBFtR-1592811187434)(images/1587638853416.png)]

Click on “renren-fast”, Can see that it will “renren-fast” All the tables are listed :

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-zs8WF2nF-1592811187437)(images/1587638968519.png)]

Select all tables , And then click “ The generated code ”, Will download “renren.zip”, Extract after decompression main Folder , Placed in “gulimall-product” Project main Directory .

The following ones module, Also operate in the same way .

But for “undo_log”, There is a problem

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-uhhiDxkk-1592811187442)(images/1587657745923.png)]

Its data type is “longblob” type , After reverse engineering , The corresponding data type is unknown :

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-php1PPU9-1592811187445)(images/1587657812283.png)]

How to solve this problem ?

8. Micro service registration center

it is to be noted that nacos Where the cluster is located server, Be sure to turn off the firewall , Otherwise, it is easy to have various problems .

build nacos colony , Then start the microservices separately , Register them with Nacos in .

  application:
    name: gulimall-coupon
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.137.14

Check the registration :

http://192.168.137.14:8848/nacos/#/serviceManagement?dataId=&group=&appName=&namespace=

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-ciJTTzO0-1592811187448)(images/1587694451601.png)]

9. Use openfen

1)、 introduce open-feign

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

2)、 Write an interface , tell SpringCLoud This interface needs to call the remote service

modify “com.bigdata.gulimall.coupon.controller.CouponController”, Add the following controller Method :

    @RequestMapping("/member/list")
    public R memberCoupons(){
    
        CouponEntity couponEntity = new CouponEntity();
        couponEntity.setCouponName("discount 20%");
        return R.ok().put("coupons",Arrays.asList(couponEntity));
    }

newly build “com.bigdata.gulimall.member.feign.CouponFeignService” Interface

@FeignClient("gulimall_coupon")
public interface CouponFeignService {
    
    @RequestMapping("/coupon/coupon/member/list")
    public R memberCoupons();
}

modify “com.bigdata.gulimall.member.GulimallMemberApplication” class , add "@EnableFeignClients":

@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients(basePackages = "com.bigdata.gulimall.member.feign")
public class GulimallMemberApplication {
    

    public static void main(String[] args) {
    
        SpringApplication.run(GulimallMemberApplication.class, args);
    }
}

​ Each method that declares an interface is the request that invokes which remote service

3)、 Enable remote call function

com.bigdata.gulimall.member.controller.MemberController

    @RequestMapping("/coupons")
    public R test(){
    
        MemberEntity memberEntity=new MemberEntity();
        memberEntity.setNickname("zhangsan");
        R memberCoupons = couponFeignService.memberCoupons();

        return memberCoupons.put("member",memberEntity).put("coupons",memberCoupons.get("coupons"));
    }

(4)、 visit http://localhost:8000/member/member/coupons

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-JpyCe4XY-1592811187450)(images/1587701348764.png)]

stop it “gulimall-coupon” service , You can see that the health value of the service displayed in the registry is 0:

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-G306E059-1592811187458)(images/1587701521184.png)]

Revisit :http://localhost:8000/member/member/coupons

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-rlqbwP8Z-1592811187463)(images/1587701587456.png)]

start-up “gulimall-coupon” service , Revisit , It's back to normal again .

10. Configuration center

1) modify “gulimall-coupon” modular

add to pom rely on :

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>

establish bootstrap.properties file , This profile will take precedence over “application.yml” load .

spring.application.name=gulimall-coupon
spring.cloud.nacos.config.server-addr=192.168.137.14:8848

2) The traditional way

To elaborate config How to use , Let's start with the original way

establish “application.properties” The configuration file , Add the following configuration content :

coupon.user.name="zhangsan"
coupon.user.age=30

modify “com.bigdata.gulimall.coupon.controller.CouponController” file , Add the following :

    @Value("${coupon.user.name}")
    private String name;
    @Value("${coupon.user.age}")
    private Integer age;

    @RequestMapping("/test")
    public R getConfigInfo(){
    
       return R.ok().put("name",name).put("age",age);
    }

start-up “gulimall-coupon” service :

visit :http://localhost:7000/coupon/coupon/test>

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-97bKJfuO-1592811187471)(images/1587716583668.png)]

There is a problem with this , If frequently modified application.properties, When frequent repackaging and deployment are required . Next we will use Nacos Configuration center to solve this problem .

3)nacos config

1、 stay Nacos In the registry , Click on “ Configuration list ”, Add configuration rule :

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-mI1orTxI-1592811187473)(images/1587716911435.png)]

DataID:gulimall-coupon

Configuration format :properties

The file naming rules are : s p r i n g . a p p l i c a t i o n . n a m e − {spring.application.name}- spring.application.name{spring.profiles.active}.${spring.cloud.nacos.config.file-extension}

${spring.application.name}: Name the micro service

${spring.profiles.active}: Indicate the configuration in which environment , Such as dev、test or info

${spring.cloud.nacos.config.file-extension}: Extension of configuration file , It can be for properties、yml etc.

2、 Check the configuration :

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-lrO8XelJ-1592811187476)(images/1587717125580.png)]

3、 modify “com.bigdata.gulimall.coupon.controller.CouponController” class , add to “@RefreshScope” annotation

@RestController
@RequestMapping("coupon/coupon")
@RefreshScope
public class CouponController {
    

This will dynamically read the configuration from the configuration center .

4、 visit :http://localhost:7000/coupon/coupon/test

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-k9AkohcZ-1592811187478)(images/1587717485283.png)]

You can see that you read nacos The latest configuration information in , And when the same configuration information is indicated , The value set in the configuration center takes precedence over the local configuration .

4)Nacos Three configuration loader schemes are supported

Nacos Support “Namespace+group+data ID” Configuration solutions for .

For details, see :https://github.com/alibaba/spring-cloud-alibaba/blob/master/spring-cloud-alibaba-docs/src/main/asciidoc-zh/nacos-config.adoc

Namespace programme

Realize environment differentiation through namespaces

The following is a configuration example :

1、 Create a namespace :

“ Namespace ”—>“ Create a namespace ”:

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-o8z8qDEY-1592811187483)(images/1587718802109.png)]

Create three namespaces , Respectively dev,test and prop

2、 Go back to the configuration list , You can see the three namespaces created

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-g7pAOhjP-1592811187488)(images/1587718889316.png)]

Now we need to dev Under the namespace , establish “gulimall-coupon.properties” Configuration rules :

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-YXEknWuW-1592811187490)(images/1587719108947.png)]

3、 visit :http://localhost:7000/coupon/coupon/test

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-vfIrvEfK-1592811187492)(images/1587721184218.png)]

It doesn't use us in dev Namespace , It's using public Namespace , What's going on here ?

see “gulimall-coupon” Service startup log :

2020-04-24 16:37:24.158  WARN 32792 --- [           main] c.a.c.n.c.NacosPropertySourceBuilder     : Ignore the empty nacos configuration and get it based on dataId[gulimall-coupon] & group[DEFAULT_GROUP]
2020-04-24 16:37:24.163  INFO 32792 --- [           main] c.a.nacos.client.config.utils.JVMUtil    : isMultiInstance:false
2020-04-24 16:37:24.169  INFO 32792 --- [           main] b.c.PropertySourceBootstrapConfiguration : Located property source: [BootstrapPropertySource {name='bootstrapProperties-gulimall-coupon.properties,DEFAULT_GROUP'}, BootstrapPropertySource {name='bootstrapProperties-gulimall-coupon,DEFAULT_GROUP'}]

"gulimall-coupon.properties", The default is public Rules configured in the contents of the namespace .

4、 Specify the namespace

If you want to make our custom namespace effective , Need to be in “bootstrap.properties” In file , Specify which namespace to use :

spring.cloud.nacos.config.namespace=a2c83f0b-e0a8-40fb-9b26-1e9d61be7d6d

This namespace ID From the namespace we created in the first step

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-LeQpsu2w-1592811187495)(images/1587718802109.png)]

5、 restart “gulimall-coupon”, Revisit :http://localhost:7000/coupon/coupon/test

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-EuirgA0H-1592811187498)(images/1587720311349.png)]

But the granularity of this namespace is not enough , To this end, we can provide each micro service for the project module Create a namespace .

6、 Create a namespace for all microservices

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-RbED1pPK-1592811187503)(images/1587720714101.png)]

7、 Go back to the configuration list tab , clone pulic Configuration rules for to coupon Under the namespace

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-lISO5efJ-1592811187506)(images/1587720883244.png)]

Switch to coupon Under the namespace , View the cloned rules :

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-nudELLFd-1592811187508)(images/1587720963699.png)]

8、 modify “gulimall-coupon” Under the bootstrap.properties file , Add the following configuration information

spring.cloud.nacos.config.namespace=7905c915-64ad-4066-8ea9-ef63918e5f79

What is indicated here is , Read with coupon Configuration under namespace .

9、 restart “gulimall-coupon”, visit :http://localhost:7000/coupon/coupon/test

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-MHf2qBm1-1592811187513)(images/1587721184218.png)]

DataID programme

By designation spring.profile.active And configuration files DataID, To read different configurations in different environments , When reading configuration , The default namespace is used public, Default group (default_group) Under the DataID.

By default ,Namespace=public,Group=DEFAULT GROUP, Default Cluster yes DEFAULT

Group programme

adopt Group Achieve environmental differentiation

example : By using different groups , To read different configurations , Or on top gulimall-coupon Microservices, for example

1、 newly build “gulimall-coupon.properties”, Put it in “tmp” Under the group

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-1bkFsDLL-1592811187516)(images/1587721616021.png)]

2、 modify “bootstrap.properties” To configure , Add the following configuration

spring.cloud.nacos.config.group=tmp

3、 restart “gulimall-coupon”, visit :http://localhost:7000/coupon/coupon/test

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-zQLQJ7a1-1592811187519)(images/1587721844449.png)]

5) Load multiple configuration sets at the same time

When the number of microservices is very large , Write all configurations into a configuration file , Obviously not very appropriate . We can configure the configuration according to different functions , Split into different configuration files .

As shown in the following configuration file :

server:
  port: 7000

spring:
  datasource:
    #MySQL To configure 
    driverClassName: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://192.168.137.14:3306/gulimall_sms?useUnicode=true&characterEncoding=UTF-8&useSSL=false
    username: root
    password: root

  application:
    name: gulimall-coupon
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.137.14:8848



mybatis-plus:
  global-config:
    db-config:
      id-type: auto
  mapper-locations: classpath:/mapper/**/*.xml


We can ,

The configuration related to the data source is written to a configuration file :

spring:
  datasource:
    #MySQL To configure 
    driverClassName: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://192.168.137.14:3306/gulimall_sms?useUnicode=true&characterEncoding=UTF-8&useSSL=false
    username: root
    password: root

The information related to the framework is written to another configuration file :

mybatis-plus:
  global-config:
    db-config:
      id-type: auto
  mapper-locations: classpath:/mapper/**/*.xml

You can also give these configurations to nacos To manage .

example : take “gulimall-coupon” Of “application.yml” The file is split into multiple configurations , And put it to nacos Configuration center

1、 establish “datasource.yml”, Used to store configuration related to data source

spring:
  datasource:
    #MySQL To configure 
    driverClassName: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://192.168.137.14:3306/gulimall_sms?useUnicode=true&characterEncoding=UTF-8&useSSL=false
    username: root
    password: root

stay coupon In the namespace , establish “datasource.yml” To configure

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-pLbr7kwv-1592811187521)(images/1587722798375.png)]

2、 Will and mybatis Related configuration , Placed in “mybatis.yml” in

mybatis-plus:
  global-config:
    db-config:
      id-type: auto
  mapper-locations: classpath:/mapper/**/*.xml

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-LwiCAn8M-1592811187525)(images/1587722710432.png)]

3、 establish “other.yml” To configure , Save other configuration information

server:
  port: 7000

spring:
  application:
    name: gulimall-coupon
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.137.14:8848

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-on81XBag-1592811187528)(images/1587722998265.png)]

Now? “mybatis.yml”、“datasource.yml” and “other.yml” Together, they constitute the configuration of microservices .

4、 modify “gulimall-coupon” Of “bootstrap.properties” file , load “mybatis.yml”、“datasource.yml” and “other.yml” To configure

spring.cloud.nacos.config.extension-configs[0].data-id=mybatis.yml
spring.cloud.nacos.config.extension-configs[0].group=dev
spring.cloud.nacos.config.extension-configs[0].refresh=true

spring.cloud.nacos.config.extension-configs[1].data-id=datasource.yml
spring.cloud.nacos.config.extension-configs[1].group=dev
spring.cloud.nacos.config.extension-configs[1].refresh=true


spring.cloud.nacos.config.extension-configs[2].data-id=other.yml
spring.cloud.nacos.config.extension-configs[2].group=dev
spring.cloud.nacos.config.extension-configs[2].refresh=true

"spring.cloud.nacos.config.ext-config" Has been abandoned , It is recommended to use “spring.cloud.nacos.config.extension-configs”

5、 notes “application.yml” All configurations in the file

6、 restart “gulimall-coupon” service , And then visit :http://localhost:7000/coupon/coupon/test

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-lZ47N6u8-1592811187535)(images/1587724212905.png)]

7、 visit :http://localhost:7000/coupon/coupon/list, Check whether the database can be accessed normally

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-di00X2hz-1592811187538)(images/1587724350548.png)]

Summary :

1)、 Microservice any configuration information , Any configuration file can be placed in the configuration center ;

2)、 Only need bootstrap.properties in , Explain which configuration files are loaded in the configuration center ;

3)、@Value, @ConfigurationProperties. Can be used to obtain the information configured in the configuration center ;

4)、 Some configuration centers give priority to , If not, use the local configuration .

11. gateway

1、 register “gulimall-gateway” To Nacos

1) establish “gulimall-gateway”

SpringCloud gateway

2) add to “gulimall-common” Dependence and “spring-cloud-starter-gateway” rely on

        <dependency>
            <groupId>com.bigdata.gulimall</groupId>
            <artifactId>gulimall-common</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>

3)“com.bigdata.gulimall.gulimallgateway.GulimallGatewayApplication” Class plus “@EnableDiscoveryClient” annotation

4) stay Nacos Created in “gateway” Namespace , Also create... In this namespace “gulimall-gateway.yml”

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-HWQRuRWu-1592811187540)(images/1587729576178.png)]

5) establish “bootstrap.properties” file , Add the following configuration , Indicate the configuration center address and namespace

spring.application.name=gulimall-gateway
spring.cloud.nacos.config.server-addr=192.168.137.14:8848
spring.cloud.nacos.config.namespace=1c82552e-1af0-4ced-9a48-26f19c2d315f

6) establish “application.properties” file , Specify the service name and registry address

spring.application.name=gulimall-gateway
spring.cloud.nacos.discovery.server-addr=192.168.137.14:8848
server.port=88

7) start-up “gulimall-gateway”

Initiate error reporting :

Description:

Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured.

Reason: Failed to determine a suitable driver class

resolvent : stay “com.bigdata.gulimall.gulimallgateway.GulimallGatewayApplication” Exclude configuration related to data source from

@SpringBootApplication(exclude = {
    DataSourceAutoConfiguration.class})

Restart

visit :http://192.168.137.14:8848/nacos/#, It is found that the service has been registered to Nacos in

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-Y7W87bfZ-1592811187543)(images/1587730035866.png)]

2、 Case study

Now I want to realize the goal of “http://localhost:88/hello?url=baidu”, Forwarding to “https://www.baidu.com”, Aim at “http://localhost:88/hello?url=qq” Request , Forwarding to “https://www.qq.com/”

1) establish “application.yml”

spring:
  cloud:
    gateway:
      routes:
        - id: baidu_route
          uri: https://www.baidu.com
          predicates:
            - Query=url, baidu
        - id: qq_route
          uri: https://www.qq.com/
          predicates:
            - Query=url, qq

2) start-up “gulimall-gateway”

3) test

visit :http://localhost:88/hello?url=baidu

visit :http://localhost:88/hello?url=qq

12. Vue

install vue

#  Latest stable version 
$ npm install vue

1、vue Declarative rendering


        let vm = new Vue({
    
            el: "#app",// Binding elements 
            data: {
      // Encapsulated data 
                name: " Zhang San ",
                num: 1
            },
            methods:{
      // Encapsulation method 
                cancle(){
    
                    this.num -- ;
                },
                hello(){
    
                    return "1"
                }
            }
        });

2、 Two way binding , Model changes , View changes . vice versa

Two way binding uses v-model

 <input type="text" v-model="num">
<h1> {
    {
    name}} , Very handsome , Yes {
    {
    num}} I like him personally {
    {
    hello()}}</h1>
1587746815353

3、 Event handling

v-xx: Instructions
1、 establish vue example , The template of the associated page , Put your own data (data) Render to the associated template , Responsive
2、 Instructions to simplify the understanding of dom Some operations of .
3、 Declare methods to do more complex operations .methods It can be encapsulated .

v-on Is the click event of the button :

 <button v-on:click="num++"> give the thumbs-up </button>

stay VUE in el,data and vue The role of :

  • el: Used to bind data ;
  • data: To encapsulate data ;
  • methods: Used to encapsulate methods , And can encapsulate multiple methods , How to encapsulate cancell and hello Method .

install “Vue 2 Snippets”, Used for code tips

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-PEArYyV3-1592811187548)(images/1587747283279.png)]

In order to facilitate debugging on the browser VUE Program , Need to install “vue-devtools”, Compile and install to chrome Then you can .

See... For detailed usage :Vue Debug artifact vue-devtools install

“v-html” Not for HTML The tag is escaped , Instead, it is displayed directly on the browser data Set content ; and “ v-text” Would be right html The tag is escaped

     <div id="app">
        {
    {
    msg}}  {
    {
    1+1}}  {
    {
    hello()}}<br/>
        <span v-html="msg"></span>
        <br/>
        <span v-text="msg"></span>
    </div>
   
    <script src="../node_modules/vue/dist/vue.js"></script>

    <script>
        new Vue({
    
            el:"#app",
            data:{
    
                msg:"<h1>Hello</h1>",
                link:"http://www.baidu.com"
            },
            methods:{
    
                hello(){
    
                    return "World"
                }
            }
        })
    </script>

Running results :

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-9wTW9Byn-1592811187552)(images/1587748494597.png)]

{ {msg}} : It is called difference expression , It must be written in Html expression , Can complete mathematical operations and method calls

4、v-bind : One way binding

to html Tag's attribute binding

 <!--  to html Tag's attribute binding  -->
    <div id="app"> 

        <a v-bind:href="link">gogogo</a>

        <!-- class,style  {
    class name : add ?}-->
        <span v-bind:class="{active:isActive,'text-danger':hasError}"
          :style="{color: color1,fontSize: size}"> Hello </span>

    </div>

    <script src="../node_modules/vue/dist/vue.js"></script>

    <script>
        let vm = new Vue({
    
            el:"#app",
            data:{
    
                link: "http://www.baidu.com",
                isActive:true,
                hasError:true,
                color1:'red',
                size:'36px'
            }
        })
    </script>

The task completed above is to give a Tag binding a hyperlink . And when the “isActive” and “hasError” All are true When , Dynamically bind attributes to , Then bind the “active” and "text-danger"class. This can dynamically adjust the existence of attributes .

And if you want to implement changes vm Of "color1" and “size”, span Elemental style Can also change with it , You can write v-bind:style, You can omit it v-bind.

5、v-model Two way binding

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>


    <!--  Form items , Custom components  -->
    <div id="app">

         Proficient language :
            <input type="checkbox" v-model="language" value="Java"> java<br/>
            <input type="checkbox" v-model="language" value="PHP"> PHP<br/>
            <input type="checkbox" v-model="language" value="Python"> Python<br/>
         Selected  {
   {language.join(",")}}
    </div>
    
    <script src="../node_modules/vue/dist/vue.js"></script>

    <script> let vm = new Vue({
      el:"#app", data:{
      language: [] } }) </script>

</body>
</html>

The function completed above is through “v-model” Bind multiple values to the input box , Can realize the selected value , stay data Of language Also constantly changing ,

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-KZNWsQKE-1592811187558)(images/image-20200425090955705.png)]

If... Is specified on the console vm.language=[“Java”,“PHP”], be data The value will also change .

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-nYpTWDes-1592811187560)(images/image-20200425091736505.png)]

adopt “v-model” Realized that the page has changed , Then the data also changes , Data changes , The page also changes , This enables two-way binding .

Array join operation : Selected { {language.join(",")}}

6、v-on Binding events for buttons

        <!-- Write directly in the event js fragment -->
        <button v-on:click="num++"> give the thumbs-up </button>
        <!-- Event specifies a callback function , Must be Vue The function defined in the instance -->
        <button @click="cancle"> Cancel </button>

The above is the click event bound for the two buttons , One of them is for num Since it increases , Another self subtraction .

v-on:click You can also write @click

The bubble of events :

        <!--  Event modifier  -->
        <div style="border: 1px solid red;padding: 20px;" v-on:click="hello">
             Big div
            <div style="border: 1px solid blue;padding: 20px;" @click="hello">
                 Small div <br />
                <a href="http://www.baidu.com" @click.prevent="hello"> Go to Baidu </a>
            </div>
        </div>

The two above are nested div in , If you click on the inner layer div, Then the outer layer div It will also be triggered ; This problem can be done with event modifiers :

        <!--  Event modifier  -->
        <div style="border: 1px solid red;padding: 20px;" v-on:click.once="hello">
             Big div
            <div style="border: 1px solid blue;padding: 20px;" @click.stop="hello">
                 Small div <br />
                <a href="http://www.baidu.com" @click.prevent.stop="hello"> Go to Baidu </a>
                <!-- Click and jump operation of hyperlink is prohibited here , And it will only trigger the operation of the current object -->
            </div>
        </div>

About event modifiers :

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-BAZP2uXq-1592811187567)(images/image-20200425094010008.png)]

Key modifier :

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-jAMe9TiO-1592811187569)(images/image-20200425094247167.png)]

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-04g7GLH9-1592811187577)(images/image-20200425100629676.png)]

7、v-for Traversal cycle

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>

<body>

    <div id="app">
        <ul>
            <li v-for="(user,index) in users" :key="user.name" v-if="user.gender == ' Woman '">
                <!-- 1、 Show user Information :v-for="item in items" -->
                Current index :{
   {index}} ==> {
   {user.name}}  ==>   {
   {user.gender}} ==>{
   {user.age}} <br>
                <!-- 2、 Get array subscript :v-for="(item,index) in items" -->
                <!-- 3、 Traversing objects : v-for="value in object" v-for="(value,key) in object" v-for="(value,key,index) in object" -->
                 Object information :
                <span v-for="(v,k,i) in user">{
   {k}}=={
   {v}}=={
   {i}};</span>
                <!-- 4、 When traversing, add :key To distinguish different data , Improve vue Rendering efficiency  -->
            </li>

            
        </ul>

        <ul>
            <li v-for="(num,index) in nums" :key="index"></li>
        </ul>
    </div>
    <script src="../node_modules/vue/dist/vue.js"></script>
    <script> let app = new Vue({
      el: "#app", data: {
      users: [{
      name: ' Liu Yan ', gender: ' Woman ', age: 21 }, {
      name: ' Zhang San ', gender: ' male ', age: 18 }, {
      name: ' Fan Bingbing ', gender: ' Woman ', age: 24 }, {
      name: ' Liu Yifei ', gender: ' Woman ', age: 18 }, {
      name: ' Gulinaza ', gender: ' Woman ', age: 25 }], nums: [1,2,3,4,4] }, }) </script>
</body>

</html>

4、 When traversing, add :key To distinguish different data , Improve vue Rendering efficiency

filter

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>

<body>
    <!--  Filters are often used to handle text formatting operations . Filters can be used in two places : Double curly braces interpolate the sum  v-bind  expression  -->
    <div id="app">
        <ul>
            <li v-for="user in userList">
                {
   {user.id}} ==> {
   {user.name}} ==> {
   {user.gender == 1?" male ":" Woman "}} ==>
                {
   {user.gender | genderFilter}} ==> {
   {user.gender | gFilter}}
                <!--  there "|" Pipe represented , take user.gender Give the value of to genderFilter -->
            </li>
        </ul>
    </div>
    <script src="../node_modules/vue/dist/vue.js"></script>

    <script> //  Global filter   Vue.filter("gFilter", function (val) {
      if (val == 1) {
      return " male ~~~"; } else {
      return " Woman ~~~"; } }) let vm = new Vue({
      el: "#app", data: {
      userList: [ {
      id: 1, name: 'jacky', gender: 1 }, {
      id: 2, name: 'peter', gender: 0 } ] }, filters: {
       filters  Define local filter , Only in the current vue Use in instance  genderFilter(val) {
      if (val == 1) {
      return " male "; } else {
      return " Woman "; } } } }) </script>
</body>

</html>

Componentization

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>

<body>

    <div id="app">
        <button v-on:click="count++"> I got clicked  {
   {count}}  Time </button>

        <counter></counter>
        <counter></counter>
        <counter></counter>
        <counter></counter>
        <counter></counter>
        <!--  Use the defined components button-counter -->
        <button-counter></button-counter>
    </div>
    <script src="../node_modules/vue/dist/vue.js"></script>


    <script> //1、 Global declaration registers a component  Vue.component("counter", {
      template: `<button v-on:click="count++"> I got clicked  {
      {count}}  Time </button>`, data() {
      return {
      count: 1 } } }); //2、 Local declaration of a component  const buttonCounter = {
      template: `<button v-on:click="count++"> I got clicked  {
      {count}}  Time ~~~</button>`, data() {
      return {
      count: 1 } } }; new Vue({
      el: "#app", data: {
      count: 1 }, components: {
      // Declare the defined local component  'button-counter': buttonCounter } }) </script>
</body>

</html>

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-gKK3lhN2-1592811187580)(images/image-20200425110048496.png)]

Life cycle hook function

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>

<body>
    <div id="app">
        <span id="num">{
   {num}}</span>
        <button @click="num++"> Fabulous !</button>
        <h2>{
   {name}}, Yes {
   {num}} Personal praise </h2>
    </div>

    <script src="../node_modules/vue/dist/vue.js"></script>
    
    <script> let app = new Vue({
      el: "#app", data: {
      name: " Zhang San ", num: 100 }, methods: {
      show() {
      return this.name; }, add() {
      this.num++; } }, beforeCreate() {
      console.log("=========beforeCreate============="); console.log(" Data model not loaded :" + this.name, this.num); console.log(" Method not loaded :" + this.show()); console.log("html Template not loaded :" + document.getElementById("num")); }, created: function () {
      console.log("=========created============="); console.log(" Data model loaded :" + this.name, this.num); console.log(" Method loaded :" + this.show()); console.log("html Template loaded :" + document.getElementById("num")); console.log("html The template is not rendered :" + document.getElementById("num").innerText); }, beforeMount() {
      console.log("=========beforeMount============="); console.log("html The template is not rendered :" + document.getElementById("num").innerText); }, mounted() {
      console.log("=========mounted============="); console.log("html Template rendered :" + document.getElementById("num").innerText); }, beforeUpdate() {
      console.log("=========beforeUpdate============="); console.log(" The data model has been updated :" + this.num); console.log("html Template not updated :" + document.getElementById("num").innerText); }, updated() {
      console.log("=========updated============="); console.log(" The data model has been updated :" + this.num); console.log("html Template updated :" + document.getElementById("num").innerText); } }); </script>
</body>

</html>

13. element ui

Official website : https://element.eleme.cn/#/zh-CN/component/installation

install

npm i element-ui -S

stay main.js Write the following in :

import ElementUI  from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css';

Vue.use(ElementUI);

14. Recursive tree structure to get data

In the registry “product” In the namespace , establish “gulimall-product.yml” The configuration file :

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-SlFqFdIM-1592811187583)(images/image-20200425153735737.png)]

take “application.yml” Copy the content to the configuration file

server:
  port: 10000

spring:
  datasource:
    #MySQL To configure 
    driverClassName: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://192.168.137.14:3306/gulimall_pms?useUnicode=true&characterEncoding=UTF-8&useSSL=false
    username: root
    password: root
  application:
    name: gulimall-product
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.137.14:8848


mybatis-plus:
  global-config:
    db-config:
      id-type: auto
  mapper-locations: classpath:/mapper/**/*.xml


Create locally “bootstrap.properties” file , Indicate the location of the configuration center and the configuration files used :

spring.application.name=gulimall-product
spring.cloud.nacos.config.server-addr=192.168.137.14:8848
spring.cloud.nacos.config.namespace=3c50ffaa-010b-4b59-9372-902e35059232
spring.cloud.nacos.config.extension-configs[0].data-id=gulimall-product.yml
spring.cloud.nacos.config.extension-configs[0].group=DEFAULT_GROUP
spring.cloud.nacos.config.extension-configs[0].refresh=true

Then start gulimall-product, You can see that the service has already appeared in nacos In the registry of

modify “com.bigdata.gulimall.product.service.CategoryService” class , Add the following code :

    /** *  list  */
    @RequestMapping("/list/tree")
    public List<CategoryEntity> list(){
    
        List<CategoryEntity> categoryEntities = categoryService.listWithTree();

        return categoryEntities;
    }

test :http://localhost:10000/product/category/list/tree

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-MlyDZsPp-1592811187586)(images/image-20200425154348716.png)]

How to distinguish which classification level ?

answer : Can be classified by parent_cid To judge , If it is a primary classification , Its value is 0.

     /** *  list  */
    @RequestMapping("/list/tree")
    public List<CategoryEntity> list(){
    
        List<CategoryEntity> categoryEntities = categoryService.listWithTree();
        // Find all primary classifications 
        List<CategoryEntity> level1Menus = categoryEntities.stream()
                .filter(item -> item.getParentCid() == 0)
                .map(menu->{
    
                    menu.setChildCategoryEntity(getChildrens(menu,categoryEntities));
                    return menu;
                })
                .sorted((menu1, menu2) -> {
    

                  return (menu1.getSort() ==null ? 0:menu1.getSort())- (menu2.getSort()==null?0:menu2.getSort());

                })
                .collect(Collectors.toList());



        return level1Menus;
    }

    public List<CategoryEntity> getChildrens(CategoryEntity root,List<CategoryEntity> all){
    

        List<CategoryEntity> childrens = all.stream().filter(item -> {
    
            return item.getParentCid() == root.getCatId();
        }).map(item -> {
    
            item.setChildCategoryEntity(getChildrens(item, all));
            return item;
        }).sorted((menu1, menu2) -> {
    
            return (menu1.getSort() ==null ? 0:menu1.getSort())- (menu2.getSort()==null?0:menu2.getSort());
        }).collect(Collectors.toList());

        return childrens;
    }

Here's what you get JSON data

[
  {
    
    "catId": 1,
    "name": " The book 、 Audio-visual 、 Electronic books and magazines ",
    "parentCid": 0,
    "catLevel": 1,
    "showStatus": 1,
    "sort": 0,
    "icon": null,
    "productUnit": null,
    "productCount": 0,
    "childCategoryEntity": [
      {
    
        "catId": 22,
        "name": " Electronic books and magazines ",
        "parentCid": 1,
        "catLevel": 2,
        "showStatus": 1,
        "sort": 0,
        "icon": null,
        "productUnit": null,
        "productCount": 0,
        "childCategoryEntity": [
          {
    
            "catId": 165,
            "name": " e-book ",
            "parentCid": 22,
            "catLevel": 3,
            "showStatus": 1,
            "sort": 0,
            "icon": null,
            "productUnit": null,
            "productCount": 0,
            "childCategoryEntity": []
          },
          {
    
            "catId": 166,
            "name": " Original on the Internet ",
            "parentCid": 22,
            "catLevel": 3,
            "showStatus": 1,
            "sort": 0,
            "icon": null,
            "productUnit": null,
            "productCount": 0,
            "childCategoryEntity": []
          },
          {
    
            "catId": 167,
            "name": " Digital magazine ",
            "parentCid": 22,
            "catLevel": 3,
            "showStatus": 1,
            "sort": 0,
            "icon": null,
            "productUnit": null,
            "productCount": 0,
            "childCategoryEntity": []
          },
          {
    
            "catId": 168,
            "name": " Multimedia books ",
            "parentCid": 22,
            "catLevel": 3,
            "showStatus": 1,
            "sort": 0,
            "icon": null,
            "productUnit": null,
            "productCount": 0,
            "childCategoryEntity": []
          }
        ]
      },
      {
    
        "catId": 23,
        "name": " Audio-visual ",
        "parentCid": 1,
        "catLevel": 2,
        "showStatus": 1,
        "sort": 0,
        "icon": null,
        "productUnit": null,
        "productCount": 0,
        "childCategoryEntity": [
          {
    
            "catId": 169,
            "name": " music ",
            "parentCid": 23,
            "catLevel": 3,
            "showStatus": 1,
            "sort": 0,
            "icon": null,
            "productUnit": null,
            "productCount": 0,
            "childCategoryEntity": []
          },
          {
    
            "catId": 170,
            "name": " Movies ",
            "parentCid": 23,
            "catLevel": 3,
            "showStatus": 1,
            "sort": 0,
            "icon": null,
            "productUnit": null,
            "productCount": 0,
            "childCategoryEntity": []
          },
          {
    
            "catId": 171,
            "name": " Educational audio-visual ",
            "parentCid": 23,
            "catLevel": 3,
            "showStatus": 1,
            "sort": 0,
            "icon": null,
            "productUnit": null,
            "productCount": 0,
            "childCategoryEntity": []
          }
        ]
      },
      {
    

Start the back-end project renren-fast

Start the front-end project renren-fast-vue:

npm run dev

visit : http://localhost:8001/#/login

Create a first level menu :

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-cHK4mM51-1592811187590)(images/image-20200425164019287.png)]

After creation , A record will be created in the background management system :

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-C6h83DlQ-1592811187596)(images/image-20200425164201813.png)]

Then create a submenu :

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-rvFLBZGk-1592811187599)(images/image-20200425164509143.png)]

establish renren-fast-vue\src\views\modules\product Catalog , So this is how to create , Because product/category, Corresponding to product-category

Under the directory , newly build “category.vue” file :


The refresh page appears 404 abnormal , View request discovery , The request is “http://localhost:8080/renren-fast/product/category/list/tree”

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-qhMEqUan-1592811187602)(images/image-20200425173615149.png)]

This request is incorrect , The correct request is :http://localhost:10000/product/category/list/tree,

Fix this problem :

Replace “static\config\index.js” In the document “window.SITE_CONFIG[‘baseUrl’]”

Before replacement :

window.SITE_CONFIG['baseUrl'] = 'http://localhost:8080/renren-fast';

After replacement :

 window.SITE_CONFIG['baseUrl'] = 'http://localhost:88/api';

http://localhost:88, This address is the interface of our gateway microservice .

Here we need to complete the path mapping through the gateway , So it will renren-fast Sign up to nacos In the registry , And add configuration center

application:
    name: renren-fast
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.137.14:8848

      config:
        name: renren-fast
        server-addr: 192.168.137.8848
        namespace: ee409c3f-3206-4a3b-ba65-7376922a886d

Configure gateway routing , All requests from the front desk are made via “http://localhost:88/api” To forward , stay “gulimall-gateway” Add routing rules to :

        - id: admin_route
          uri: lb://renren-fast
          predicates:
            - Path=/api/**

But doing so introduces another problem , Revisit :http://localhost:8001/#/login, It is found that the verification code is no longer displayed :

The analysis reason :

  1. The current verification code request path is ,http://localhost:88/api/captcha.jpg?uuid=69c79f02-d15b-478a-8465-a07fd09001e6
  2. Original verification code request path :http://localhost:8001/renren-fast/captcha.jpg?uuid=69c79f02-d15b-478a-8465-a07fd09001e6

stay admin_route Under the routing rules of , The access path contains “api”, So it will forward it to renren-fast, When the gateway forwards , Will use the prefix information of the gateway , In order to get the verification code normally , We need to rewrite the request path

About request path rewriting :

6.16. The RewritePathGatewayFilter Factory

The RewritePathGatewayFilter factory takes a path regexp parameter and a replacement parameter. This uses Java regular expressions for a flexible way to rewrite the request path. The following listing configures a RewritePathGatewayFilter:

Example 41. application.yml

spring:
  cloud:
    gateway:
      routes:
      - id: rewritepath_route
        uri: https://example.org
        predicates:
        - Path=/foo/**
        filters:
        - RewritePath=/red(?<segment>/?.*), $\{
    segment}

For a request path of /red/blue, this sets the path to /blue before making the downstream request. Note that the $ should be replaced with $\ because of the YAML specification.

modify “admin_route” Routing rules :

        - id: admin_route
          uri: lb://renren-fast
          predicates:
            - Path=/api/**
          filters:
            - RewritePath=/api/(?<segment>/?.*), /renren-fast/$\{
    segment}

Revisit :http://localhost:8001/#/login, The verification code can be loaded normally .

But unfortunately, new problems have arisen , Access denied

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-mZejna2W-1592811187610)(images/image-20200425192722821.png)]

Problem description : Cross source requests have been blocked : The same origin policy prohibits reading from http://localhost:88/api/sys/login Remote resources .( reason :CORS Head missing ‘Access-Control-Allow-Origin’).

Problem analysis : This is a cross domain problem . The domain name and port accessed are different from the original request , The request will be restricted

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-2LETXWL7-1592811187612)(images/image-20200425192902637.png)]

Cross domain processes :

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-6MrZHm88-1592811187621)(images/image-20200425193136641.png)]

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-QFx1OdXq-1592811187630)(images/image-20200425193523849.png)]

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-yGQ7rKkT-1592811187632)(images/image-20200425193614185.png)]

resolvent : In gateway definition “GulimallCorsConfiguration” class , This class is used for filtering , Allow all requests to cross domain .

@Configuration
public class GulimallCorsConfiguration {
    

    @Bean
    public CorsWebFilter corsWebFilter(){
    
        UrlBasedCorsConfigurationSource source=new UrlBasedCorsConfigurationSource();
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.addAllowedHeader("*");
        corsConfiguration.addAllowedMethod("*");
        corsConfiguration.addAllowedOrigin("*");
        corsConfiguration.setAllowCredentials(true);
        
        source.registerCorsConfiguration("/**",corsConfiguration);
        return new CorsWebFilter(source);
    }
}

Revisit :http://localhost:8001/#/login

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-u1H0PfSO-1592811187679)(images/image-20200425195437299.png)]

http://localhost:8001/renre Cross source requests have been blocked : The same origin policy prohibits reading from http://localhost:88/api/sys/login Remote resources .( reason : It is not allowed to have more than one ‘Access-Control-Allow-Origin’ CORS head )n-fast/captcha.jpg?uuid=69c79f02-d15b-478a-8465-a07fd09001e6

Multiple requests have occurred , And there are multiple cross source requests .

To solve this problem , Need modification renren-fast project , Comment out “io.renren.config.CorsConfig” class . Then visit again .

When displaying classification information , There is 404 abnormal , Requested http://localhost:88/api/product/category/list/tree non-existent

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-n4uvoJ4U-1592811187683)(images/image-20200425213240724.png)]

This is because the path mapping on the gateway is incorrect , The mapped path is http://localhost:8001/renren-fast/product/category/list/tree

But only through http://localhost:10000/product/category/list/tree The path can be accessed normally , So I will report 404 abnormal .

The solution is to define a product Routing rules , Path rewriting :

        - id: product_route
          uri: lb://gulimall-product
          predicates:
            - Path=/api/product/**
          filters:
            - RewritePath=/api/(?<segment>/?.*),/$\{
    segment}

In the order of routing rules , Put the precise routing rules in front of the fuzzy routing rules , Otherwise , Precise routing rules will not be matched to , Similar to... In an abnormal system try catch The order in which exceptions are handled in clause .

15. Delete data

add to delete and append identification , And add a check box

 <el-tree
    :data="menus"
    show-checkbox  // Show check boxes 
    :props="defaultProps"  
    :expand-on-click-node="false" // Set the node not to expand when clicked 
    node-key="catId"   
  >
    <span class="custom-tree-node" slot-scope="{ node, data }">
      <span>{
   { node.label }}</span>
      <span>
        <el-button v-if="node.level <= 2" type="text" size="mini" @click="() => append(data)">Append</el-button>
        <el-button
          v-if="node.childNodes.length == 0"
          type="text"
          size="mini"
          @click="() => remove(node, data)"
        >Delete</el-button>
      </span>
    </span>
  </el-tree>

Test delete data , open postman Input “ http://localhost:88/api/product/category/delete ”, The request mode is set to POST, In order to compare the effect , You can query the database before deleting pms_category surface :

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-eToJD8X9-1592811187688)(images/image-20200426112814069.png)]

because delete The request receives an array , So here we use JSON The way , An array was passed in :

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-fKd0Flyr-1592811187702)(images/image-20200426113003531.png)]

Query the database again to see cat_id by 1000 Has been deleted .

modify “com.bigdata.gulimall.product.controller.CategoryController” class , Add the following code :

 @RequestMapping("/delete")
    public R delete(@RequestBody Long[] catIds){
    
        // Before deleting, you need to judge whether the menu to be deleted is referenced elsewhere .
// categoryService.removeByIds(Arrays.asList(catIds));

        categoryService.removeMenuByIds(Arrays.asList(catIds));
        return R.ok();
    }

com.bigdata.gulimall.product.service.impl.CategoryServiceImpl

    @Override
    public   void removeMenuByIds(List<Long> asList) {
    
        //TODO  Check if the current menu is referenced elsewhere 
        categoryDao.deleteBatchIds(asList);
    }

But most of the time , We don't want to delete data , Instead, mark that it has been deleted , This is logical deletion ;

You can set show_status by 0, Mark that it has been deleted .

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-fxXLROgB-1592811187705)(images/image-20200426115332899.png)]

mybatis-plus Logical deletion of :

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-1YqnuHFN-1592811187709)(images/image-20200426115420393.png)]

Configure global logical deletion rules , stay “src/main/resources/application.yml” Add the following to the file :

mybatis-plus:
  global-config:
    db-config:
      id-type: auto
      logic-delete-value: 1
      logic-not-delete-value: 0

modify “com.bigdata.gulimall.product.entity.CategoryEntity” class , add @TableLogic, Indicates the use of logical deletion :

	/** *  Whether or not shown [0- No display ,1 Show ] */
	@TableLogic(value = "1",delval = "0")
	private Integer showStatus;

And then in POSTMan Test whether it can meet the needs . In addition to “src/main/resources/application.yml” In file , Set the log level , Print out SQL sentence :

logging:
  level:
    com.bigdata.gulimall.product: debug

Printed logs :

 ==>  Preparing: UPDATE pms_category SET show_status=0 WHERE cat_id IN ( ? ) AND show_status=1 
 ==> Parameters: 1431(Long)
 <==    Updates: 1
 get changedGroupKeys:[]

16. Menu drag

Drag in the same menu normal
Drag to the front or back of the parent menu normal
Drag to another menu at the same level of the parent menu normal

The focus of attention is , Drag to the target node , Make the target node catlevel+deep Less than 3 that will do . The conditions before and after dragging to the target node are , bring

You need to change the order and level when dragging the menu

Two types of nodes need to be considered catLevel

One relationship is : If the child nodes under the same node move back and forth , There is no need to modify its catLevel

If you drag it into another node or into the parent node , Consider modifying its catLevel

If you drag it into a node relationship at the same level as the parent node , The node to be dragged catLevel, Set as a sibling node Level,

Think about it first parentCid Think about it first catLevel?

The two relationships are coupled

There is also a case of dragging back and forth

Which range is the largest ?

It must be the drag type that has the greatest relationship ,

If you drag back and forth , After dragging, you need to look at the level of the dragged node and set the level of the node to be dragged parentId,

​ If the level of the node to be dragged is the same as that of the target node , It is considered as peer dragging , Just modify the order of nodes ;

​ Otherwise, it is considered as cross level dragging , You need to modify the level and reset parentID

​ If

​ Divide by drag type , Inappropriate , Cross level dragging and peer dragging are more appropriate

How to determine whether to drag across levels or at the same level , According to the dragging level , If you are dragging at the same level , You just need to change the order , But there is also a problem , When dragging to the same level directory under another group , Obviously, it also needs to be modified parentID, What kind of model is the best ?

In addition, it can also be judged that when moving across levels , Cross level parentID Are they the same? , If it's not the same , It is considered that the cross level movement under different directories needs to be modified parentID.

The order 、catLevel and parentID

Peer move :

(1) First of all, judge the nodes to be moved and the target nodes catLevel Are they the same? ,

(2) The same is considered as peer movement ,

​ If the target node is moved at this time parentID The same as that of the node to be moved , But the movement type is back and forth , Just adjust the order , At this time, the movement type is inner, It needs to be modified catLevel and parentId And order

​ If the target node is moved at this time parentID Different from the node to be moved , But the movement type is back and forth , You need to adjust the order and parentId, At this time, the movement type is inner, It needs to be modified catLevel and parentId And order

Through these two steps, we can see some commonalities , If you extract a movement type as a large category , Under this classification ,

If it is moving back and forth , It can be divided into the following situations :

​ Move back and forth at the same level : The definition standard is catLevel identical , But it can be divided into parentID Same and parentID Different ,parent Phase at the same time , Just change the order ;parentID Different time , Need modification parentID And order

​ Move back and forth at different levels : The definition standard is catLevel Different , At this point, it should be modified anyway parentID, The order and catLevel

If it is inner Type move , It can be divided into the following situations .

​ At this time, no matter at the same level inner, Or cross level innner, They all need to be modified parentID, The order and catLevel

In which case do you need to update child nodes ?

It depends on whether the node to be dragged contains child nodes , If there are child nodes , You need to update the child nodes catLevel, There is no need to update the order between it and parentId, Just update catLevel that will do . This kind of updating the child nodes Level It should be classified , The current goal is to update it whenever there are child nodes catLevel,

(2) If the nodes to be moved and the target nodes catLevel Different , It is considered as cross level movement . If you are moving to the parent node , You need to set catLevel,parentID And order . At this point, we need to consider two situations , If you are moving to the parent node , You need to set catLevel,parentID And order , If you are moving to a sibling node , You need to set

Contains moves to the parent node sibling Directory , Sibling node .

Set menu drag switch

 <el-switch v-model="draggable" active-text=" Turn on drag and drop " inactive-text=" Turn off drag and drop "></el-switch>

But the problem now is that every time you drag , Will send requests , Update the database so frequently to interact with the database , Now I want to implement a drag and drop process without updating the database , When the drag is done , Submit the dragged data uniformly .

There is still a problem , If you drag and drop a menu continuously , Finally, it was put in its original position , however updateNode There are many node update information in , This is obviously a problem .

Batch deletion

  <el-button type="danger" plain size="small" @click="batchDelete"> Batch deletion </el-button>
 // Batch deletion 
    batchDelete() {
    
      let checkNodes = this.$refs.menuTree.getCheckedNodes();

      // console.log(" The selected node :",checkNodes);

      let catIds = [];
      for (let i = 0; i < checkNodes.length; i++) {
    
        catIds.push(checkNodes[i].catId);
      }

      this.$confirm(` Are you sure you want to delete ?`, " Tips ", {
    
        confirmButtonText: " determine ",
        cancelButtonText: " Cancel ",
        type: "warning"
      })
        .then(() => {
    
          this.$http({
    
            url: this.$http.adornUrl("/product/category/delete"),
            method: "post",
            data: this.$http.adornData(catIds, false)
          }).then(({
     data }) => {
    
            this.$message({
    
              message: " Menu batch deletion succeeded ",
              type: "success"
            });

            // Refresh the page 
            this.getMeus();
          });


        })
        .catch(() => {
    
          // Cancel deletion 
        });
    },

17. Brand management menu

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-fTeRiPCn-1592811187715)(images/image-20200428164054517.png)]

(2) take “” From reverse engineering resources\src\views\modules\product File copy to gulimall/renren-fast-vue/src/views/modules/product Under the table of contents , These are the following two files

brand.vue brand-add-or-update.vue

But the displayed page has no new and delete functions , This is because of permission control ,

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-rXkWFWhw-1592811187723)(images/image-20200428170325515.png)]

<el-button v-if="isAuth('product:brand:save')" type="primary" @click="addOrUpdateHandle()"> newly added </el-button>
<el-button v-if="isAuth('product:brand:delete')" type="danger" @click="deleteHandle()" :disabled="dataListSelections.length <= 0"> Batch deletion </el-button>
      

see “isAuth” The definition of location :

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-1KYPC8ae-1592811187727)(images/image-20200428170437592.png)]

It's in “index.js” In the definition of , Now set it to return a value of true, Add and remove functions can be displayed .

Refresh the page again to see , The button has already appeared :

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-G7fp9afJ-1592811187736)(images/image-20200428170644511.png)]

add to “ Display status button ”

brand.vue

<template slot-scope="scope">
  <el-switch
    v-model="scope.row.showStatus"
    active-color="#13ce66"
    inactive-color="#ff4949"
    @change="updateBrandStatus(scope.row)"
    :active-value = "1"
    :inactive-value	= "0"
  ></el-switch>
</template>

brand-add-or-update.vue

 <el-form-item label=" Display state " prop="showStatus">
    <el-switch v-model="dataForm.showStatus" active-color="#13ce66" inactive-color="#ff4949"></el-switch>
 </el-form-item>
// Update the status of the switch 
    updateBrandStatus(data) {
    
      console.log(" The latest state ", data);
      let {
    brandId,showStatus} = data;
      this.$http({
    
        url: this.$http.adornUrl("/product/brand/update"),
        method: "post",
        data: this.$http.adornData({
    brandId,showStatus}, false)
      }).then(({
     data }) => {
    

        this.$message({
    
          message: " Status update successful ",
          type: "success"
        });

      });
    },

Add upload

Unlike traditional monomer applications , Here we choose to upload the data to the distributed file server .

Here we choose to place the picture on Alibaba cloud , Use object store .

Using object storage on Alibaba cloud :

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-SUpXiCaN-1592811187738)(images/image-20200428182755992.png)]

establish Bucket

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-OpPTckfY-1592811187740)(images/image-20200428183041570.png)]

Upload files :

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-iswkk8Yi-1592811187744)(images/image-20200428183213694.png)]

After successful upload , Get a picture of URL

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-z9egVYqU-1592811187748)(images/image-20200428183644020.png)]

This way is to upload pictures manually , In fact, we can set up the program to automatically upload pictures to Alibaba cloud object storage .

Upload model :

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-8nk61A9C-1592811187753)(images/image-20200428184029655.png)]

Check Alibaba cloud's help on file upload : https://help.aliyun.com/document_detail/32009.html?spm=a2c4g.11186623.6.768.549d59aaWuZMGJ

1) Add dependency package

stay Maven Add dependencies to the project ( Recommend ways )

stay Maven Use in engineering OSS Java SDK, Just in pom.xml Add the corresponding dependency in . With 3.8.0 Version as an example , stay Add the following in :

<dependency>
    <groupId>com.aliyun.oss</groupId>
    <artifactId>aliyun-sdk-oss</artifactId>
    <version>3.8.0</version>
</dependency>

2) Upload file stream

The following code is used to upload the file stream :

// Endpoint Take hangzhou for example , Other Region Please fill in according to the actual situation .
String endpoint = "http://oss-cn-hangzhou.aliyuncs.com";
//  Cloud accounts AccessKey Have all API Access right , It is recommended to follow Alibaba cloud security best practices , Create and use RAM The sub account number is used for API Visit or daily operations , Please log in  https://ram.console.aliyun.com  establish .
String accessKeyId = "<yourAccessKeyId>";
String accessKeySecret = "<yourAccessKeySecret>";

//  establish OSSClient example .
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

//  Upload file stream .
InputStream inputStream = new FileInputStream("<yourlocalFile>");
ossClient.putObject("<yourBucketName>", "<yourObjectName>", inputStream);

//  close OSSClient.
ossClient.shutdown();

endpoint The value of :

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-W4K686yq-1592811187758)(images/image-20200428190553350.png)]

accessKeyId and accessKeySecret You need to create a RAM account number :

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-E8FAkEk9-1592811187764)(images/image-20200428190532924.png)]

After creating the user , You'll get one “AccessKey ID” and “AccessKeySecret”, Then copy these two values to the code “AccessKey ID” and “AccessKeySecret”.

You also need to add access control permissions :

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-nfTS6aDz-1592811187768)(images/image-20200428191518591.png)]

@Test
    public void testUpload() throws FileNotFoundException {
    
        // Endpoint Take hangzhou for example , Other Region Please fill in according to the actual situation .
        String endpoint = "oss-cn-shanghai.aliyuncs.com";
        //  Cloud accounts AccessKey Have all API Access right , It is recommended to follow Alibaba cloud security best practices , Create and use RAM The sub account number is used for API Visit or daily operations , Please log in  https://ram.console.aliyun.com  establish .
        String accessKeyId = "LTAI4G4W1RA4JXz2QhoDwHhi";
        String accessKeySecret = "R99lmDOJumF2x43ZBKT259Qpe70Oxw";

        //  establish OSSClient example .
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

        //  Upload file stream .
        InputStream inputStream = new FileInputStream("C:\\Users\\Administrator\\Pictures\\timg.jpg");
        ossClient.putObject("gulimall-images", "time.jpg", inputStream);

        //  close OSSClient.
        ossClient.shutdown();
        System.out.println(" Upload successful .");
    }

A simpler way to use , It's using SpringCloud Alibaba

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-D1V7LI5V-1592811187770)(images/image-20200428195507730.png)]

Detailed usage , see : https://help.aliyun.com/knowledge_detail/108650.html

(1) Add dependency

        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alicloud-oss</artifactId>
            <version>2.2.0.RELEASE</version>
        </dependency>

(2) establish “AccessKey ID” and “AccessKeySecret”

(3) To configure key,secret and endpoint Related information

      access-key: LTAI4G4W1RA4JXz2QhoDwHhi
      secret-key: R99lmDOJumF2x43ZBKT259Qpe70Oxw
      oss:
        endpoint: oss-cn-shanghai.aliyuncs.com

(4) Inject OSSClient And upload and download files

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-InuZvGEn-1592811187773)(images/image-20200428224840535.png)]

But it's still troublesome to do so , If the future upload tasks are assigned to gulimall-product To complete , Obviously, the coupling is high . It's best to create a new one Module To complete the file upload task .

The other way

1) newly build gulimall-third-party

2) Add dependency , Original gulimall-common Medium “spring-cloud-starter-alicloud-oss” Dependency moved to the project

        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alicloud-oss</artifactId>
            <version>2.2.0.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>com.bigdata.gulimall</groupId>
            <artifactId>gulimall-common</artifactId>
            <version>1.0-SNAPSHOT</version>
            <exclusions>
                <exclusion>
                    <groupId>com.baomidou</groupId>
                    <artifactId>mybatis-plus-boot-starter</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

In addition, it also needs to be in “pom.xml” In file , Add the following dependency management

<dependencyManagement>

        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>2.2.1.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

3) Start the service registration and discovery in the main startup class

@EnableDiscoveryClient

4) stay nacos Register in

(1) Create a namespace “ gulimall-third-party ”

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-E2l8xCBz-1592811187778)(images/image-20200429075831984.png)]

(2) stay “ gulimall-third-party” In the namespace , establish “ gulimall-third-party.yml” file

spring:
  cloud:
    alicloud:
      access-key: LTAI4G4W1RA4JXz2QhoDwHhi
      secret-key: R99lmDOJumF2x43ZBKT259Qpe70Oxw
      oss:
        endpoint: oss-cn-shanghai.aliyuncs.com

5) Writing configuration files

application.yml

server:
  port: 30000

spring:
  application:
    name: gulimall-third-party
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.137.14:8848

logging:
  level:
    com.bigdata.gulimall.product: debug

bootstrap.properties

spring.cloud.nacos.config.name=gulimall-third-party
spring.cloud.nacos.config.server-addr=192.168.137.14:8848
spring.cloud.nacos.config.namespace=f995d8ee-c53a-4d29-8316-a1ef54775e00
spring.cloud.nacos.config.extension-configs[0].data-id=gulimall-third-party.yml
spring.cloud.nacos.config.extension-configs[0].group=DEFAULT_GROUP
spring.cloud.nacos.config.extension-configs[0].refresh=true

6) Writing test classes

package com.bigdata.gulimall.thirdparty;

import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.OSSClientBuilder;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;

@SpringBootTest
class GulimallThirdPartyApplicationTests {
    


    @Autowired
    OSSClient ossClient;

    @Test
    public void testUpload() throws FileNotFoundException {
    
        // Endpoint Take hangzhou for example , Other Region Please fill in according to the actual situation .
        String endpoint = "oss-cn-shanghai.aliyuncs.com";
        //  Cloud accounts AccessKey Have all API Access right , It is recommended to follow Alibaba cloud security best practices , Create and use RAM The sub account number is used for API Visit or daily operations , Please log in  https://ram.console.aliyun.com  establish .
        String accessKeyId = "LTAI4G4W1RA4JXz2QhoDwHhi";
        String accessKeySecret = "R99lmDOJumF2x43ZBKT259Qpe70Oxw";

        //  establish OSSClient example .
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

         // Upload file stream .
        InputStream inputStream = new FileInputStream("C:\\Users\\Administrator\\Pictures\\timg.jpg");
        ossClient.putObject("gulimall-images", "time3.jpg", inputStream);

        //  close OSSClient.
        ossClient.shutdown();
        System.out.println(" Upload successful .");
    }

}

https://help.aliyun.com/document_detail/31926.html?spm=a2c4g.11186623.6.1527.228d74b8V6IZuT

background

use JavaScript Client direct signature ( See JavaScript Client signature direct transmission ) when ,AccessKeyID and AcessKeySecret Will be exposed to the front page , So there are serious security risks . therefore ,OSS This paper provides a scheme of direct transmission after server signature .

Principle introduction

img

The principle of direct transmission after server signature is as follows :

  1. User sends upload Policy Request to the application server .
  2. The application server returns the upload Policy And sign to the user .
  3. Users upload data directly to OSS.

To write “com.bigdata.gulimall.thirdparty.controller.OssController” class :

package com.bigdata.gulimall.thirdparty.controller;

import com.aliyun.oss.OSS;
import com.aliyun.oss.common.utils.BinaryUtil;
import com.aliyun.oss.model.MatchMode;
import com.aliyun.oss.model.PolicyConditions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.Map;

@RestController
public class OssController {
    

    @Autowired
    OSS ossClient;
    @Value ("${spring.cloud.alicloud.oss.endpoint}")
    String endpoint ;

    @Value("${spring.cloud.alicloud.oss.bucket}")
    String bucket ;

    @Value("${spring.cloud.alicloud.access-key}")
    String accessId ;
    @Value("${spring.cloud.alicloud.secret-key}")
    String accessKey ;
    @RequestMapping("/oss/policy")
    public Map<String, String> policy(){
    

        String host = "https://" + bucket + "." + endpoint; // host The format is  bucketname.endpoint

        String format = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
        String dir = format; //  The prefix specified by the user when uploading the file .

        Map<String, String> respMap=null;
        try {
    
            long expireTime = 30;
            long expireEndTime = System.currentTimeMillis() + expireTime * 1000;
            Date expiration = new Date(expireEndTime);
            PolicyConditions policyConds = new PolicyConditions();
            policyConds.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE, 0, 1048576000);
            policyConds.addConditionItem(MatchMode.StartWith, PolicyConditions.COND_KEY, dir);

            String postPolicy = ossClient.generatePostPolicy(expiration, policyConds);
            byte[] binaryData = postPolicy.getBytes("utf-8");
            String encodedPolicy = BinaryUtil.toBase64String(binaryData);
            String postSignature = ossClient.calculatePostSignature(postPolicy);

            respMap= new LinkedHashMap<String, String>();
            respMap.put("accessid", accessId);
            respMap.put("policy", encodedPolicy);
            respMap.put("signature", postSignature);
            respMap.put("dir", dir);
            respMap.put("host", host);
            respMap.put("expire", String.valueOf(expireEndTime / 1000));

        } catch (Exception e) {
    
            // Assert.fail(e.getMessage());
            System.out.println(e.getMessage());
        } finally {
    
            ossClient.shutdown();
        }
        return respMap;
    }
}

test : http://localhost:30000/oss/policy

{"accessid":"LTAI4G4W1RA4JXz2QhoDwHhi","policy":"eyJleHBpcmF0aW9uIjoiMjAyMC0wNC0yOVQwMjo1ODowNy41NzhaIiwiY29uZGl0aW9ucyI6W1siY29udGVudC1sZW5ndGgtcmFuZ2UiLDAsMTA0ODU3NjAwMF0sWyJzdGFydHMtd2l0aCIsIiRrZXkiLCIyMDIwLTA0LTI5LyJdXX0=","signature":"s42iRxtxGFmHyG40StM3d9vOfFk=","dir":"2020-04-29/","host":"https://gulimall-images.oss-cn-shanghai.aliyuncs.com","expire":"1588129087"}

The access path when uploading files in the future is “ http://localhost:88/api/thirdparty/oss/policy”,

stay “gulimall-gateway” Configure routing rules in :

        - id: third_party_route
          uri: lb://gulimall-gateway
          predicates:
            - Path=/api/thirdparty/**
          filters:
            - RewritePath=/api/thirdparty/(?<segment>/?.*),/$\{
    segment}

Test whether it can jump normally : http://localhost:88/api/thirdparty/oss/policy

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-vM4fOLXN-1592811187792)(images/image-20200429111408164.png)]

Upload components

Place the... Provided by the project upload Folder to components Under the table of contents , One is single file upload , The other is multi file upload

PS D:\Project\gulimall\renren-fast-vue\src\components\upload> ls


     Catalog : D:\Project\gulimall\renren-fast-vue\src\components\upload


Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-a----  2020/4/29  Wednesday      12:0           3122 multiUpload.vue
                                2
-a----  2019/11/11  Monday      21:            343 policy.js
                               20
-a----  2020/4/29  Wednesday      12:0           3053 singleUpload.vue
                                1


PS D:\Project\gulimall\renren-fast-vue\src\components\upload>

After modifying the configuration of these two files

Start uploading , But in the process of uploading , There are the following problems :

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-6UZPjmIu-1592811187799)(images/image-20200429124629150.png)]

Access to XMLHttpRequest at 'http://gulimall-images.oss-cn-shanghai.aliyuncs.com/' from origin 'http://localhost:8001' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.

This is another cross domain problem , The solution is to enable cross domain access on alicloud :

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-83isV45C-1592811187802)(images/image-20200429124940091.png)]

Perform file upload again .

18. JSR303 check

step 1: Use validation annotations

stay Java A series of verification methods are provided in , It uses these verification methods in “javax.validation.constraints” In bag , Provided as @Email,@NotNull Etc .

The non empty processing method provides @NotNull,@Blank and @

(1)@NotNull

The annotated element must not be null. Accepts any type.
Annotation elements must not be null, Capable of receiving any type

(2)@NotEmpty

the annotated element must not be null nor empty.

The field modified by this annotation cannot be null or ""

Supported types are:

The following types are supported

CharSequence (length of character sequence is evaluated)

Character sequence ( Calculation of the length of character sequence )

Collection (collection size is evaluated)
Calculation of set length

Map (map size is evaluated)
map Calculation of length

Array (array length is evaluated)
Calculation of array length

(3)@NotBlank

The annotated element must not be null and must contain at least one non-whitespace character. Accepts CharSequence.
The annotation cannot be null, And contain at least one non white space character . Receive character sequence .

step 2: In the request method , Use validation annotations @Valid, Turn on verification ,

    @RequestMapping("/save")
    public R save(@Valid @RequestBody BrandEntity brand){
    
		brandService.save(brand);

        return R.ok();
    }

test : http://localhost:88/api/product/brand/save

stay postman Send the above request

{
    
    "timestamp": "2020-04-29T09:20:46.383+0000",
    "status": 400,
    "error": "Bad Request",
    "errors": [
        {
    
            "codes": [
                "NotBlank.brandEntity.name",
                "NotBlank.name",
                "NotBlank.java.lang.String",
                "NotBlank"
            ],
            "arguments": [
                {
    
                    "codes": [
                        "brandEntity.name",
                        "name"
                    ],
                    "arguments": null,
                    "defaultMessage": "name",
                    "code": "name"
                }
            ],
            "defaultMessage": " Can't be empty ",
            "objectName": "brandEntity",
            "field": "name",
            "rejectedValue": "",
            "bindingFailure": false,
            "code": "NotBlank"
        }
    ],
    "message": "Validation failed for object='brandEntity'. Error count: 1",
    "path": "/product/brand/save"
}

Be able to see "defaultMessage": “ Can't be empty ”, These error messages are defined in “hibernate-validator” Of “\org\hibernate\validator\ValidationMessages_zh_CN.properties” In file . Many error rules are defined in this file :

javax.validation.constraints.AssertFalse.message     =  Only for false
javax.validation.constraints.AssertTrue.message      =  Only for true
javax.validation.constraints.DecimalMax.message      =  Must be less than or equal to {value}
javax.validation.constraints.DecimalMin.message      =  Must be greater than or equal to {value}
javax.validation.constraints.Digits.message          =  The value of the number is out of the allowed range ( Only in {integer} Bit integers and {fraction} In decimal places )
javax.validation.constraints.Email.message           =  Not a legal email address 
javax.validation.constraints.Future.message          =  Need is a future time 
javax.validation.constraints.FutureOrPresent.message =  Need is a future or present time 
javax.validation.constraints.Max.message             =  Maximum not exceeding {value}
javax.validation.constraints.Min.message             =  The minimum cannot be less than {value}
javax.validation.constraints.Negative.message        =  It has to be negative 
javax.validation.constraints.NegativeOrZero.message  =  Must be negative or zero 
javax.validation.constraints.NotBlank.message        =  Can't be empty 
javax.validation.constraints.NotEmpty.message        =  Can't be empty 
javax.validation.constraints.NotNull.message         =  Not for null
javax.validation.constraints.Null.message            =  It has to be for null
javax.validation.constraints.Past.message            =  Need is a past time 
javax.validation.constraints.PastOrPresent.message   =  Need is a past or present time 
javax.validation.constraints.Pattern.message         =  Need to match regular expression "{regexp}"
javax.validation.constraints.Positive.message        =  It must be a positive number 
javax.validation.constraints.PositiveOrZero.message  =  Must be positive or zero 
javax.validation.constraints.Size.message            =  The number must be in {min} and {max} Between 

org.hibernate.validator.constraints.CreditCardNumber.message        =  Illegal credit card number 
org.hibernate.validator.constraints.Currency.message                =  Illegal currency  ( Must be {value} One of them )
org.hibernate.validator.constraints.EAN.message                     =  illegal {type} Bar code 
org.hibernate.validator.constraints.Email.message                   =  Not a legal email address 
org.hibernate.validator.constraints.Length.message                  =  The length needs to be in {min} and {max} Between 
org.hibernate.validator.constraints.CodePointLength.message         =  The length needs to be in {min} and {max} Between 
org.hibernate.validator.constraints.LuhnCheck.message               = ${validatedValue} The check code of is illegal , Luhn model 10 Checksum mismatch 
org.hibernate.validator.constraints.Mod10Check.message              = ${validatedValue} The check code of is illegal ,  model 10 Checksum mismatch 
org.hibernate.validator.constraints.Mod11Check.message              = ${validatedValue} The check code of is illegal ,  model 11 Checksum mismatch 
org.hibernate.validator.constraints.ModCheck.message                = ${validatedValue} The check code of is illegal , ${modType} Checksum mismatch 
org.hibernate.validator.constraints.NotBlank.message                =  Can't be empty 
org.hibernate.validator.constraints.NotEmpty.message                =  Can't be empty 
org.hibernate.validator.constraints.ParametersScriptAssert.message  =  Execute script expression "{script}" No return of expected results 
org.hibernate.validator.constraints.Range.message                   =  Need to be in {min} and {max} Between 
org.hibernate.validator.constraints.SafeHtml.message                =  There may be unsafe HTML Content 
org.hibernate.validator.constraints.ScriptAssert.message            =  Execute script expression "{script}" No return of expected results 
org.hibernate.validator.constraints.URL.message                     =  Need to be a legal URL

org.hibernate.validator.constraints.time.DurationMax.message        =  Must be less than ${inclusive == true ? ' Or equal to ' : ''}${days == 0 ? '' : days += ' God '}${hours == 0 ? '' : hours += ' Hours '}${minutes == 0 ? '' : minutes += ' minute '}${seconds == 0 ? '' : seconds += ' second '}${millis == 0 ? '' : millis += ' millisecond '}${nanos == 0 ? '' : nanos += ' nanosecond '}
org.hibernate.validator.constraints.time.DurationMin.message        =  Must be greater than ${inclusive == true ? ' Or equal to ' : ''}${days == 0 ? '' : days += ' God '}${hours == 0 ? '' : hours += ' Hours '}${minutes == 0 ? '' : minutes += ' minute '}${seconds == 0 ? '' : seconds += ' second '}${millis == 0 ? '' : millis += ' millisecond '}${nanos == 0 ? '' : nanos += ' nanosecond '}

Want to customize error messages , You can override the default error message , Such as @NotBlank Default message yes

public @interface NotBlank {
    

	String message() default "{javax.validation.constraints.NotBlank.message}";

You can add comments , modify message:

	@NotBlank(message = " Brand name must be non empty ")
	private String name;

When the request is sent again , Get the error message :

{
    
    "timestamp": "2020-04-29T09:36:04.125+0000",
    "status": 400,
    "error": "Bad Request",
    "errors": [
        {
    
            "codes": [
                "NotBlank.brandEntity.name",
                "NotBlank.name",
                "NotBlank.java.lang.String",
                "NotBlank"
            ],
            "arguments": [
                {
    
                    "codes": [
                        "brandEntity.name",
                        "name"
                    ],
                    "arguments": null,
                    "defaultMessage": "name",
                    "code": "name"
                }
            ],
            "defaultMessage": " Brand name must be non empty ",
            "objectName": "brandEntity",
            "field": "name",
            "rejectedValue": "",
            "bindingFailure": false,
            "code": "NotBlank"
        }
    ],
    "message": "Validation failed for object='brandEntity'. Error count: 1",
    "path": "/product/brand/save"
}

However, the returned error results do not meet our business needs .

step 3: For verification Bean after , Next to a BindResult, You can get the result of verification . Get the verification result , You can customize the encapsulation .

 @RequestMapping("/save")
    public R save(@Valid @RequestBody BrandEntity brand, BindingResult result){
    
        if( result.hasErrors()){
    
            Map<String,String> map=new HashMap<>();
            //1. Get the wrong verification result 
            result.getFieldErrors().forEach((item)->{
    
                // Get the... When an error occurs message
                String message = item.getDefaultMessage();
                // Get the field where the error occurred 
                String field = item.getField();
                map.put(field,message);
            });
            return R.error(400," The submitted data is illegal ").put("data",map);
        }else {
    

        }
		brandService.save(brand);

        return R.ok();
    }

This is to set a content verification for the request , If you configure it separately for each request , Obviously not very appropriate , In fact, exceptions can be handled uniformly .

step 4: Unified exception handling

have access to SpringMvc Provided by the @ControllerAdvice, adopt “basePackages” It can explain which paths to handle exceptions .

(1) Extract an exception handling class

package com.bigdata.gulimall.product.exception;

import com.bigdata.common.utils.R;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import java.util.HashMap;
import java.util.Map;

/** *  Centralized handling of all exceptions  */
@Slf4j
@RestControllerAdvice(basePackages = "com.bigdata.gulimall.product.controller")
public class GulimallExceptionAdvice {
    


    @ExceptionHandler(value = Exception.class)
    public R handleValidException(MethodArgumentNotValidException exception){
    
        Map<String,String> map=new HashMap<>();
        BindingResult bindingResult = exception.getBindingResult();
        bindingResult.getFieldErrors().forEach(fieldError -> {
    
            String message = fieldError.getDefaultMessage();
            String field = fieldError.getField();
            map.put(field,message);
        });

        log.error(" There is a problem with data verification {}, Exception types {}",exception.getMessage(),exception.getClass());
        return R.error(400," There is a problem with data verification ").put("data",map);
    }

}

(2) test : http://localhost:88/api/product/brand/save

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-zXDE3h1R-1592811187804)(images/image-20200429183334783.png)]

(3) Default exception handling

   @ExceptionHandler(value = Throwable.class)
    public R handleException(Throwable throwable){
    
        log.error(" Unknown exception {}, Exception types {}",throwable.getMessage(),throwable.getClass());
        return R.error(BizCodeEnum.UNKNOW_EXEPTION.getCode(),BizCodeEnum.UNKNOW_EXEPTION.getMsg());
    }

(4) Error status code

In the above code , For error status code , We define it at will , However, in the formal development process , Error status codes have strict definition rules , For example, in this project, our error status code definition

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-qgQaoDTj-1592811187823)(images/image-20200429183748249.png)]

To define these error status codes , We can define a constant class separately , Used to store these error status codes

package com.bigdata.common.exception;

/*** *  Error code and error message definition class  * 1.  The error code definition rule is 5 Is the number  * 2.  The first two are business scenarios , The last three digits indicate the error code . for example :100001.10: Universal  001: System unknown exception  * 3.  After maintaining the error code, you need to maintain the error description , Define them as enumeration forms  *  Error code list : * 10:  Universal  * 001: Parameter format verification  * 11:  goods  * 12:  Order  * 13:  The shopping cart  * 14:  logistics  */
public enum BizCodeEnum {
    

    UNKNOW_EXEPTION(10000," System unknown exception "),

    VALID_EXCEPTION( 10001," Parameter format validation failed ");

    private int code;
    private String msg;

    BizCodeEnum(int code, String msg) {
    
        this.code = code;
        this.msg = msg;
    }

    public int getCode() {
    
        return code;
    }

    public String getMsg() {
    
        return msg;
    }
}

(5) test : http://localhost:88/api/product/brand/save

image-20200429191830967

19. Group verification function ( Complete the complex verification of multiple scenarios )

1、 Give verification comments , On the label groups, Specify when verification is required

Such as : Specify when updating and adding , All need to be verified

	@NotEmpty
	@NotBlank(message = " Brand name must be non empty ",groups = {
    UpdateGroup.class,AddGroup.class})
	private String name;

under these circumstances , There is no verification annotation for the specified group , Default doesn't work . To work, you have to add groups.

2、 Business method parameters are used @Validated annotation

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-92rUWWRh-1592811187831)(C:\Users\ Piglets \AppData\Local\Temp\1591255963395.png)]

@Validated Of value Method :

Specify one or more validation groups to apply to the validation step kicked off by this annotation.
Specify one or more validation groups to apply to the validation steps initiated by this annotation .

JSR-303 defines validation groups as custom annotations which an application declares for the sole purpose of using
them as type-safe group arguments, as implemented in SpringValidatorAdapter.

JSR-303 Define the validation group as a custom comment , The only purpose of application declarations is to use them as type safety group parameters , Such as SpringValidatorAdapter As implemented in .

Other SmartValidator implementations may support class arguments in other ways as well.

other SmartValidator Implementations can also support class parameters in other ways .

3、 By default , In the case of group verification , There is no verification annotation for the specified group , It won't work , It will only take effect without grouping .

20. Custom verification function

1、 Write a custom verification annotation


@Documented
@Constraint(validatedBy = {
     ListValueConstraintValidator.class})
@Target({
     METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
@Retention(RUNTIME)
public @interface ListValue {
    
    String message() default "{com.bigdata.common.valid.ListValue.message}";

    Class<?>[] groups() default {
     };

    Class<? extends Payload>[] payload() default {
     };

    int[] value() default {
    };
}

2、 Write a custom checker


public class ListValueConstraintValidator implements ConstraintValidator<ListValue,Integer> {
    
    private Set<Integer> set=new HashSet<>();
    @Override
    public void initialize(ListValue constraintAnnotation) {
    
        int[] value = constraintAnnotation.value();
        for (int i : value) {
    
            set.add(i);
        }

    }

    @Override
    public boolean isValid(Integer value, ConstraintValidatorContext context) {
    


        return  set.contains(value);
    }
}

3、 Associated with custom validator and custom validation annotation

@Constraint(validatedBy = {
     ListValueConstraintValidator.class})

4、 Using examples

	/** *  Display state [0- No display ;1- Show ] */
	@ListValue(value = {
    0,1},groups ={
    AddGroup.class})
	private Integer showStatus;

21. goods SPU and SKU management

Re execution “sys_menus.sql”

22. Click on the sub component , The parent component triggers an event

Now you want to click on the left side of the menu , It can display data on the right

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-ARw4wYRx-1592811187833)(images/image-20200430215649355.png)]

Parent child component passing data :

1) The child component passes data to the parent component , Event mechanism ;

stay category In the binding node-click event ,

  <el-tree :data="menus" :props="defaultProps" node-key="catId" ref="menuTree" @node-click="nodeClick"	></el-tree>

2) The child component sends an event to the parent component , Carry the data ;

    nodeClick(data,Node,component){
    
       console.log(" Child components ",data,Node,component);
       this.$emit("tree-node-click",data,Node,component);
    }, 

this.$emit( Event name ,“ Carrying data ”);

3) Get the event sent in the parent component

<category @tree-node-click="treeNodeClick"></category>
    // Get the event data sent 
    treeNodeClick(data,Node,component){
    
     console.log("attgroup Perceived category The node is clicked ",data,Node,component);
     console.log(" The menu just clicked ID",data.catId);
    },

4) Backstage method

23. Specifications and parameters are added VO

When adding a specification parameter , Requested URL:Request URL:

http://localhost:88/api/product/attr/base/list/0?t=1588731762158&page=1&limit=10&key=

When there are new fields , We tend to be in entity Create a new field in the entity class , And mark that the field does not exist in the database , However, this method is not standardized

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-ahqvLaFc-1592811187838)(images/1588732021702.png)]

The more standardized approach is , Create a new one vo Folder , Put each different object , It is divided according to its functions . stay java in , These types are involved

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-SIPJBkR6-1592811187840)(images/1588732152646.png)]

Request URL: http://localhost:88/api/product/attr/save, Now the situation is , When it's stored , It's just preserved attr, Not saved attrgroup, To solve this problem , We built a new one vo/AttrVo, In the original AttrEntity On the basis of attrGroupId Field , When saving new data , It also preserves the relationship between them .

adopt " BeanUtils.copyProperties(attr,attrEntity);" It can be realized in two Bean Copy data between , But the two one. Bean The fields of should be the same

   @Override
    public void saveAttr(AttrVo attr) {
    
        AttrEntity attrEntity = new AttrEntity();
        BeanUtils.copyProperties(attr,attrEntity);
        this.save(attrEntity);
    }

problem : There are now two queries , One is the query part , The other is to query all , But is it necessary to do so ? Still necessary , But it can be designed in the background , Both queries are based on catId Whether it is zero .

24. Query grouping association properties and delete associations

Get all the attributes associated with the attribute group

API:https://easydoc.xyz/doc/75716633/ZUqEdvA4/LnjzZHPj

Send a request :/product/attrgroup/{attrgroupId}/attr/relation

Get the attribute associated with the current attribute group

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-tclcOK6w-1592811187843)(images/1588766303205.png)]

How to find : Now that you have given attr_group_id, Then go to the intermediate table to find the associated attr_id, Then get all the final attributes .

May appear null Value problem

25. Query the properties not associated with the group

/product/attrgroup/{attrgroupId}/noattr/relation

API:https://easydoc.xyz/doc/75716633/ZUqEdvA4/d3EezLdO

Get other basic attributes in this category that have not been associated in the attribute group , Easy to add new associations

Request URL: http://localhost:88/api/product/attrgroup/1/noattr/relation?t=1588780783441&page=1&limit=10&key=

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-eu4piobl-1592811187851)(images/1588780868214.png)]

Attribute grouping , Corresponding to “pms_attr_group” surface , Under each group , You need to view the associated attribute information , The sales attribute does not need to be associated with the group , But the specification parameter should be associated with the attribute group .

Specifications : Corresponding to pms_attr surface ,attr_type=1, Group information needs to be displayed

Sales attributes : Corresponding to pms_attr` surface ,attr_type=0, There is no need to display grouping information

grouping ID by 9 The grouping :Request URL: http://localhost:88/api/product/attrgroup/9/noattr/relation?t=1588822258669&page=1&limit=10&key=

Corresponding database fields

attr_group_id attr_group_name sort descript icon catelog_id


        9   The main body                     1   model   platform                    wu               454
       10   The graphics card                     1   Memory capacity                     wu               454
       11   input device                   1   mouse   keyboard                    wu               454
       12   a main board                     1   Graphics card type   Chipset                 wu               454
       13   specifications                     1   Size                       wu               454

Inquire about attrgroupId=9 Attribute grouping :
Inquire about attrgroupId=9 Attribute grouping :

AttrGroupEntity attrGroupEntity = attrGroupDao.selectById(attrgroupId);

Get classification information :

 Long catelogId = attrGroupEntity.getCatelogId();

The goal is : Gets other properties that are not associated with the property group

That is to get attrgroupId=9 In the attribute group of , Related categories catelog_id =454 ( Desktop computer ), Other basic properties

In this attribute group , Now the associated attributes :

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-UbuLZOBS-1592811187853)(images/1588822997675.png)]

Under this category , What are the basic properties ?

There are no other properties associated with

Properties already associated , How are these attributes related ?

answer : When creating specification parameters , You have set which attribute groups to associate .

Want to know what has not yet been linked , Check which are associated first , How to exclude these is irrelevant

The relationship between attributes and attribute groups is displayed in the middle table , All the attributes are displayed in the attribute table ,

First query the intermediate table , Get all the associated attributes id, Then query the attribute table again , Exclude the properties that have been associated ID, Put the remaining attributes ID And attributes

26. Add an association between attributes and groups

Request type :Request URL: http://localhost:88/api/product/attrgroup/attr/relation

Request mode :POST

Request data :[{“attrId”:10,“attrGroupId”:9}]

API:https://easydoc.xyz/doc/75716633/ZUqEdvA4/VhgnaedC

The response data :

{
    
	"msg": "success",
	"code": 0
}

The essence is to show in the middle pms_attr_attrgroup_relation in , The process of adding a record

27. Release commodities

Get all member levels :/member/memberlevel/list

API:https://easydoc.xyz/doc/75716633/ZUqEdvA4/jCFganpf

stay “gulimall-gateway” Revision in China “” file , Add to member The routing

        - id: gulimall-member
          uri: lb://gulimall-member
          predicates:
            - Path=/api/member/**
          filters:
            - RewritePath=/api/(?<segment>/?.*),/$\{
    segment}

stay “gulimall-member” in , establish “bootstrap.properties” file , The contents are as follows :

spring.cloud.nacos.config.name=gulimall-member
spring.cloud.nacos.config.server-addr=192.168.137.14:8848
spring.cloud.nacos.config.namespace=795521fa-77ef-411e-a8d8-0889fdfe6964
spring.cloud.nacos.config.extension-configs[0].data-id=gulimall-member.yml
spring.cloud.nacos.config.extension-configs[0].group=DEFAULT_GROUP
spring.cloud.nacos.config.extension-configs[0].refresh=true

Get the brand associated with the classification :/product/categorybrandrelation/brands/list

API:https://easydoc.xyz/doc/75716633/ZUqEdvA4/HgVjlzWV

encounter PubSub problem

  1. First installation pubsub-js
`npm install --save pubsub-js`
  1. Subscriber component
`import PubSub from 'pubsub-js'`

The this.PubSub by PubSub.

Get all groups under the category & Association attribute

Request type :/product/attrgroup/{catelogId}/withattr

Request mode :GET

request URL:http://localhost:88/api/product/attrgroup/225/withattr?t=1588864569478

mysql The default isolation level is read committed , In order to be able to , Get the data information in the database , You can adjust the isolation level to read uncommitted :

SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;

But it works for the current transaction window , If you want to set the global , Need to add global Field .

28. Commodity management

When new :

t: 1588983621569
status: 0
key: 
brandId: 0
catelogId: 0
page: 1
limit: 10

When on the shelf :

t: 1588983754030
status: 1
key: 
brandId: 0
catelogId: 0
page: 1
limit: 10

On the next shelf :

t: 1588983789089
status: 2
key: 
brandId: 0
catelogId: 0
page: 1
limit: 10

stay SPU in , The date data written out does not conform to the rules :
[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-YvY9APEY-1592811187862)(images/image-20200509083248660.png)]

Want to conform to the rules , You can set rules for writing out data :

spring.jackson

  jackson:
    date-format: yyyy-MM-dd HH:mm:ss

SKU retrieval :

Request URL: http://localhost:88/api/product/skuinfo/list?t=1588989437944&page=1&limit=10&key=&catelogId=0&brandId=0&min=0&max=0

Request body :

t: 1588989437944
page: 1
limit: 10
key: 
catelogId: 0
brandId: 0
min: 0
max: 0

API: https://easydoc.xyz/doc/75716633/ZUqEdvA4/ucirLq1D

29. Warehouse management

Inventory information table :wms_ware_info

【1】 Warehouse list function :

【2】 Check the inventory of goods :

【3】 Query purchase demand :

【4】 Merge purchasing requirements :

Select... To consolidate the whole document parcharseID:Request URL: http://localhost:88/api/ware/purchase/merge

Request data :

{
    purchaseId: 1, items: [1, 2]}
items: [1, 2]

No... Is selected for consolidation of the whole document parcharseID :Request URL: http://localhost:88/api/ware/purchase/merge

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-Wab67gZT-1592811187864)(images/image-20200509170916557.png)]

items: [1, 2]

It involves two tables :wms_purchase_detail,wms_purchase

Now fill in the data in the purchase order , Then associate users , After associating users ,

The general meaning , According to the information in the purchase order , Update purchasing requirements , Fill in the purchasing personnel in the purchase order , Po No , When purchasing , Update the purchasing personnel in the purchasing details table ID And purchase status .

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-WySY6fGP-1592811187868)(images/image-20200509191108806.png)]

Collect purchase order

http://localhost:88/api/ware/purchase/received

(1) When someone gets a purchase order , First, check whether the purchase order is in unassigned status , Only when the purchase order is new or in collection status , To update the status of the purchase order

(2)

【1】 Warehouse list function : https://easydoc.xyz/doc/75716633/ZUqEdvA4/mZgdqOWe

【2】 Check the inventory of goods : https://easydoc.xyz/doc/75716633/ZUqEdvA4/hwXrEXBZ

【3】 Query purchase demand : https://easydoc.xyz/doc/75716633/ZUqEdvA4/Ss4zsV7R

【4】 Merge purchasing requirements :https://easydoc.xyz/doc/75716633/ZUqEdvA4/cUlv9QvK

【5】 Query for unclaimed purchase orders : https://easydoc.xyz/doc/75716633/ZUqEdvA4/hI12DNrH

【6】 Collect purchase order : https://easydoc.xyz/doc/75716633/ZUqEdvA4/vXMBBgw1

Complete procurement , In the process of purchasing , It needs to involve setting SKU Of name Information into the warehouse , This is through remote calls “gulimall-product” To achieve according to sku_id You can find sku_name Of , If an exception occurs in this process , The transaction does not want to rollback , The current method is to catch exceptions , Prevent transaction rollback , Is there any other way ? This problem is left to be solved later .

 @Override
    public void addStock(Long skuId, Long wareId, Integer skuNum) {
    

        List<WareSkuEntity> wareSkuEntities = wareSkuDao.selectList(new QueryWrapper<WareSkuEntity>().eq("sku_id", skuId).eq("ware_id", wareId));

        if(wareSkuEntities == null || wareSkuEntities.size() ==0 ){
    
             // newly added 
            WareSkuEntity wareSkuEntity = new WareSkuEntity();
            wareSkuEntity.setSkuId(skuId);
            wareSkuEntity.setWareId(wareId);
            wareSkuEntity.setStock(skuNum);
            wareSkuEntity.setStockLocked(0);

            // Remote query SKU Of name, If it fails, there is no need to rollback 
            try {
    
                R info = productFeignService.info(skuId);
                if(info.getCode() == 0){
    
                    Map<String,Object> data=(Map<String,Object>)info.get("skuInfo");
                    wareSkuEntity.setSkuName((String) data.get("skuName"));
                }
            } catch (Exception e) {
    

            }

            wareSkuDao.insert(wareSkuEntity);
        }else{
    
            // Insert 
            wareSkuDao.addStock(skuId,wareId,skuNum);
        }

    }

30. obtain spu specifications

stay SPU Manage Pages , When getting product specifications , appear 400 abnormal , The browser display cannot jump

Problem phenomenon :

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-CJxXYCXx-1592811187873)(images/image-20200510182051355.png)]

The code in question :

    attrUpdateShow(row) {
    
      console.log(row);
      this.$router.push({
    
        path: "/product-attrupdate",
        query: {
     spuId: row.id, catalogId: row.catalogId }
      });
    },

I don't know how to solve the problem . It can only be left to be solved later .

Found by testing , The problem has nothing to do with the code above , The problem is “attrupdate.vue” On , The vue The page cannot be accessed through the browser , When entering access URL( http://localhost:8001/#/product-attrupdate ) When , Will appear 404, Other requests do not , I don't know why .

adopt POSTMAN When making a request , Able to request data .

After analysis, we found that , Because there is no navigation of this page in the database , To fix this problem , Can be in “sys-menu” Add a row to the table , Content bit :

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-kCJ4nrtV-1592811187875)(images/image-20200510231012714.png)]

So when you visit again , stay “ Platform properties ” Next , There will be “ Specification maintenance ” menu ,

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-WTy9JZDH-1592811187880)(images/image-20200510231041708.png)]

When you click again “ specifications ” When , The menu is displayed

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-OkwzayQz-1592811187883)(images/image-20200510231200130.png)]

But this kind of menu doesn't meet our needs , We need to make it pop up .

31. Modify product specifications

API: https://easydoc.xyz/doc/75716633/ZUqEdvA4/GhnJ0L85

URL:/product/attr/update/{spuId}

Summary :

1. stay open fen The called data will be converted to JSON, After receiving , take JSON Convert to object , At this point, the processing of the caller and callee JSON The objects of are not necessarily the same class , As long as their field types match .

The caller :

@FeignClient(value = "gulimall-coupon")
public interface CouponFenService {
    

    @PostMapping("/coupon/spubounds/save")
    R saveSpuBounds(@RequestBody SpuBoundTo spuBoundTo);

    @PostMapping("/coupon/skufullreduction/saveInfo")
    R saveSkuReduction(@RequestBody SkuReductionTo skuReductionTo);
}

Called party :

    @PostMapping("/save")
    public R save(@RequestBody SpuBoundsEntity spuBounds){
    
		spuBoundsService.save(spuBounds);

        return R.ok();
    }

    @PostMapping("/saveInfo")
    public R saveInfo(@RequestBody SkuReductionTo skuReductionTo){
    
        skuFullReductionService.saveSkuReduction(skuReductionTo);
        return R.ok();
    }

The caller JSON The object at the time of materialization SpuBoundTo:

@Data
public class SpuBoundTo {
    private Long spuId;
    private BigDecimal buyBounds;
    private BigDecimal growBounds;
}

Called party JSON Objects when data is objectified SpuBoundsEntity:

/** *  goods spu Integral setting  * * @author cosmoswong * @email [email protected] * @date 2020-04-23 23:38:48 */
@Data
@TableName("sms_spu_bounds")
public class SpuBoundsEntity implements Serializable {
    
	private static final long serialVersionUID = 1L;

	/** * id */
	@TableId
	private Long id;
	/** * */
	private Long spuId;
	/** *  Growth points  */
	private BigDecimal growBounds;
	/** *  Shopping points  */
	private BigDecimal buyBounds;
	/** *  Effectiveness of the offer [1111( Four status bits , From right to left );0 -  No preference , Whether growth points are given ;1 -  No preference , Whether shopping points are given away ;2 -  Have a discount , Whether growth points are given ;3 -  Have a discount , Whether shopping points are given away 【 Status bit 0: No gift ,1: Give 】] */
	private Integer work;

}

2. How to add to the transaction ?

There is Batch During operation , Only then needs to add the transaction , There is no need to add transaction control to a single operation .

SpringBoot In is the transaction

Batch operation , Only then needs the transaction

A transaction annotation method , Methods contain these operations :

(1) Batch update fields in a table

(2) Update operations in multiple tables

In fact, no matter what type , Method for all database writes , Will be treated as a whole transaction , During this transaction , If an exception occurs in an operation , The whole will not be submitted . This is for SpringBoot Medium @Transactional The understanding of the .

@EnableTransactionManagement and @Transactional The difference between ?

https://blog.csdn.net/abysscarry/article/details/80189232
https://blog.csdn.net/Driver_tu/article/details/99679145

https://www.cnblogs.com/leaveast/p/11765503.html

other

1. Document reference address

http://www.jayh.club/#/02.PassJava%E6%9E%B6%E6%9E%84%E7%AF%87/01.%E5%88%9B%E5%BB%BA%E9%A1%B9%E7%9B%AE%E5%92%8C%E6%B7%BB%E5%8A%A0%E6%A8%A1%E5%9D%97

https://blog.csdn.net/ok_wolf/article/details/105400748

https://www.cnblogs.com/javalbb/p/12690862.html

https://blog.csdn.net/ok_wolf/article/details/105456170

https://easydoc.xyz/doc/75716633/ZUqEdvA4/jCFganpf

2. Boot up docker

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-TsxlfQTs-1592811187885)(images/image-20200422221237751.png)]

stay Docker Set the boot container in

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-Zo3HzLVO-1592811187892)(images/image-20200423005200485.png)]

# View firewall status 
[[email protected] module]# systemctl status firewalld
  firewalld.service - firewalld - dynamic firewall daemon
   Loaded: loaded (/usr/lib/systemd/system/firewalld.service; enabled; vendor preset: enabled)
   Active: active (running) since Wed 2020-04-22 21:26:23 EDT; 10min ago
     Docs: man:firewalld(1)
 Main PID: 5947 (firewalld)
   CGroup: /system.slice/firewalld.service
           └─5947 /usr/bin/python -Es /usr/sbin/firewalld --nofork --nopid

Apr 22 21:26:20 hadoop-104 systemd[1]: Starting firewalld - dynamic firewall daemon...
Apr 22 21:26:23 hadoop-104 systemd[1]: Started firewalld - dynamic firewall daemon.
# Check whether the firewall is started 
[[email protected] module]# systemctl list-unit-files|grep firewalld
firewalld.service                             enabled 
# Turn off and start the firewall 
[[email protected] module]# systemctl disable firewalld 
Removed symlink /etc/systemd/system/multi-user.target.wants/firewalld.service.
Removed symlink /etc/systemd/system/dbus-org.fedoraproject.FirewallD1.service.
# Stop firewall 
[[email protected] module]# systemctl stop firewalld 
# Check the firewall again 
[[email protected] module]# systemctl list-unit-files|grep firewalld
firewalld.service                             disabled
[[email protected] module]# 

3. View the installation location of the command

whereis mysql: see mysql Installation position of

4. vscode Generate code snippets in

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-mJmr9yuy-1592811187896)(images/image-20200425165814903.png)]

Create a new global code fragment , The name is vue, And then go back :

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-FbbkeBtv-1592811187899)(images/image-20200425165929332.png)]

Paste the following code snippet into “vue.code-snippets”

{
    
    // Place your  overall situation  snippets here. Each snippet is defined under a snippet name and has a scope, prefix, body and 
    // description. Add comma separated ids of the languages where the snippet is applicable in the scope field. If scope 
    // is left empty or omitted, the snippet gets applied to all languages. The prefix is what is 
    // used to trigger the snippet and the body will be expanded and inserted. Possible variables are: 
    // $1, $2 for tab stops, $0 for the final cursor position, and ${1:label}, ${2:another} for placeholders. 
    // Placeholders with the same ids are connected.
    // Example:
    // "Print to console": {
    
    // "scope": "javascript,typescript",
    // "prefix": "log",
    // "body": [
    // "console.log('$1');",
    // "$2"
    // ],
    // "description": "Log output to console"
    // }
    " Generate vue Templates ": {
    
        "prefix": "vue",
        "body": [
            "<!-- $1 -->",
            "<template>",
            "<div class='$2'>$5</div>",
            "</template>",
            "",
            "<script>",
            "// Here you can import other files ( such as : Components , Tools js, Third party plug-ins js,json file , Picture files and so on )",
            "// for example :import 《 Component name 》 from '《 Component path 》';",
            "",
            "export default {",
            "//import The introduced components need to be injected into the object to be used ",
            "components: {},",
            "data() {",
            "// Here's the data ",
            "return {",
            "",
            "};",
            "},",
            "// Listener attribute   Be similar to data Concept ",
            "computed: {},",
            "// monitor data Data changes in ",
            "watch: {},",
            "// Method set ",
            "methods: {",
            "",
            "},",
            "// Life cycle  -  The creation is complete ( You can access the current this example )",
            "created() {",
            "",
            "},",
            "// Life cycle  -  Mount complete ( You can visit DOM Elements )",
            "mounted() {",
            "",
            "},",
            "beforeCreate() {}, // Life cycle  -  Before creation ",
            "beforeMount() {}, // Life cycle  -  Before mounting ",
            "beforeUpdate() {}, // Life cycle  -  Before updating ",
            "updated() {}, // Life cycle  -  After the update ",
            "beforeDestroy() {}, // Life cycle  -  Before destruction ",
            "destroyed() {}, // Life cycle  -  Destruction complete ",
            "activated() {}, // If the page has keep-alive Caching function , This function triggers ",
            "}",
            "</script>",
            "<style lang='scss' scoped>",
            "//@import url($3);  Introduce public css class ",
            "$4",
            "</style>"
        ],
        "description": " Generate VUE Templates "
    },
    "http-get request ": {
    
        "prefix": "httpget",
        "body": [
            "this.\\$http({",
            "url: this.\\$http.adornUrl(''),",
            "method: 'get',",
            "params: this.\\$http.adornParams({})",
            "}).then(({ data }) => {",
            "})"
        ],
        "description": "httpGET request "
    },
    "http-post request ": {
    
        "prefix": "httppost",
        "body": [
            "this.\\$http({",
            "url: this.\\$http.adornUrl(''),",
            "method: 'post',",
            "data: this.\\$http.adornData(data, false)",
            "}).then(({ data }) => { });"
        ],
        "description": "httpPOST request "
    }
}

See... For more details : https://blog.csdn.net/z772330927/article/details/105730430/

5. vscode Shortcut key

ctrl+shift+f Global search

alt+shift+f formatting code

6. close eslint The grammar check of

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-pk6I8WCK-1592811187903)(images/image-20200428171043110.png)]


7. install mybatisx plug-in unit

stay Marketplace Mid search “mybatisx”, Restart after installation IDEA, When in use, it will automatically be in @Mapper On the marked interface , Generate small icons , then alt+enter,generate statement, Will automatically in xml Generate... In file SQL.

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-qHJWCKlY-1592811187909)(images/1588730028929.png)]

8. mysql Batch deletion of

DELETE FROM  `pms_attr_attrgroup_relation` WHERE (attr_id= ? AND attr_group_id ) OR (attr_id= ? AND attr_group_id )

9. String.join

java.lang.String @NotNull 
public static String join(@NotNull CharSequence delimiter,
                          @NotNull Iterable<? extends CharSequence> elements)

Returns a new String composed of copies of the CharSequence elements joined together with a copy of the specified delimiter.

Returns a CharSequence A new string consisting of a copy of the element and a copy of the specified separator .

For example,

 List<String> strings = new LinkedList<>();
 strings.add("Java");strings.add("is");
 strings.add("cool");
 String message = String.join(" ", strings);
 //message returned is: "Java is cool"

 Set<String> strings = new LinkedHashSet<>();
 strings.add("Java"); strings.add("is");
 strings.add("very"); strings.add("cool");
 String message = String.join("-", strings);
 //message returned is: "Java-is-very-cool"

Note that if an individual element is null, then “null” is added.

Be careful , If a single element is null, Then add “null”.

Params:
delimiter – a sequence of characters that is used to separate each of the elements in the resulting String
The character sequence used to separate each element in the result string

elements – an Iterable that will have its elements joined together.
An iteratable... That links its elements together .

Returns:
a new String that is composed from the elements argument
from elements A new string composed of parameters

Throws:
NullPointerException – If delimiter or elements is null

    public static String join(CharSequence delimiter,
            Iterable<? extends CharSequence> elements) {
    
        Objects.requireNonNull(delimiter);
        Objects.requireNonNull(elements);
        StringJoiner joiner = new StringJoiner(delimiter);
        for (CharSequence cs: elements) {
    
            joiner.add(cs);
        }
        return joiner.toString();
    }

You can see that it is actually created by StringJoiner, Then traverse elements, Add each element to complete .

StringJoiner

java.util public final class StringJoiner
extends Object

StringJoiner is used to construct a sequence of characters separated by a delimiter and optionally starting with a supplied prefix and ending with a supplied suffix.
tringJoiner Used to construct character sequences separated by delimiters , You can choose to start with the prefix provided , End with the supplied suffix .

Prior to adding something to the StringJoiner, its sj.toString() method will, by default, return prefix + suffix. However, if the setEmptyValue method is called, the emptyValue supplied will be returned instead. This can be used, for example, when creating a string using set notation to indicate an empty set, i.e. “{}”, where the prefix is “{”, the suffix is “}” and nothing has been added to the StringJoiner.
In the StringJoiner Before adding content , its sj.toString() Method returns the prefix by default + suffix . however , If the setEmptyValue Method , Returns the provided emptyValue. for example , When using set Symbol creates a string to represent an empty set , This method can be used .“{}”, Where the prefix is “{”, Suffix is “}”, Not to StringJoiner Add anything .

apiNote:
The String “[George:Sally:Fred]” may be constructed as follows:

 StringJoiner sj = new StringJoiner(":", "[", "]");
 sj.add("George").add("Sally").add("Fred");
 String desiredString = sj.toString();

A StringJoiner may be employed to create formatted output from a java.util.stream.Stream using java.util.stream.Collectors.joining(CharSequence). For example:
Use StringJoiner from java.util.stream Create a formatted output stream , Use java.util.stream.Collectors.joining (CharSequence Conduct ). for example :

 List<Integer> numbers = Arrays.asList(1, 2, 3, 4);
 String commaSeparatedNumbers = numbers.stream()
     .map(i -> i.toString())
     .collect(Collectors.joining(", "));

Through the analysis of the source code found , stay “” One was maintained internally StringBuilder, All elements added to it will be spliced with a delimiter first , And then we can splice the added elements

 public StringJoiner add(CharSequence newElement) {
    
        prepareBuilder().append(newElement);
        return this;
 }
   private StringBuilder prepareBuilder() {
    
        if (value != null) {
    
            value.append(delimiter);
        } else {
    
            value = new StringBuilder().append(prefix);
        }
        return value;
    }

10. stay Service When there are a lot of micro Services , You can configure some micro services to be placed in compound in , Form a group

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-KHeUfPI8-1592811187912)(images/image-20200508222508833.png)]

When running later , Choose this compound You can easily run or stop a group of microservices :

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-kqrpN2JG-1592811187920)(images/image-20200508223524543.png)]

In addition, it can serve each micro service separately , Set the required maximum heap memory size at runtime :

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-DHs3IpOC-1592811187922)(images/image-20200508222812353.png)]

11. mysql Of dateTime and timestamp The difference between ?

MySQL in datetime and timestamp The difference and use of

TIMESTAMP and DATETIME Similarities :

1> Both can be used to express YYYY-MM-DD HH:MM:SS[.fraction] Date of type .

TIMESTAMP and DATETIME The difference between :

1> They are not stored in the same way

about TIMESTAMP, It converts the time inserted by the client from the current time zone to UTC( World standard time ) For storage . When inquiring , Convert it to the current time zone of the client to return .

And for DATETIME, Don't make any changes , It's basically the original input and output .

2> The two can store different time ranges

timestamp The range of time that can be stored is :‘1970-01-01 00:00:01.000000’ To ‘2038-01-19 03:14:07.999999’.

datetime The range of time that can be stored is :‘1000-01-01 00:00:00.000000’ To ‘9999-12-31 23:59:59.999999’.

summary :TIMESTAMP and DATETIME Except that the storage range and storage mode are different , There's no big difference . Of course , For business across time zones ,TIMESTAMP More appropriate .

https://www.cnblogs.com/Jashinck/p/10472398.html

12. SpringBoot The transaction

https://blog.csdn.net/Z__Sheng/article/details/89489053

13. IDEA RESTFUll clinet

IntelliJ IDEA Use rest client

FAQ

1. TypeError: _vm.previewHandle is not a function

原网站

版权声明
本文为[Pig man blogs]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/02/202202170528338828.html