当前位置:网站首页>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
[ 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>

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 :
- The current verification code request path is ,http://localhost:88/api/captcha.jpg?uuid=69c79f02-d15b-478a-8465-a07fd09001e6
- 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 RewritePath
GatewayFilter
Factory
The RewritePath
GatewayFilter
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 RewritePath
GatewayFilter
:
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
The principle of direct transmission after server signature is as follows :
- User sends upload Policy Request to the application server .
- The application server returns the upload Policy And sign to the user .
- 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

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
- First installation pubsub-js
`npm install --save pubsub-js`
- 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
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
FAQ
1. TypeError: _vm.previewHandle is not a function
边栏推荐
- 挖财商学院证券开户安全嘛?
- Matrix fast power notes
- Using baijiafan to automatically generate API calls: progress in JS (II)
- MySQL Performance Monitoring and SQL statements
- Linux下安裝Mysql【詳細】
- 一键部署属于自己的社区论坛
- Update mysql5.6 to 5.7 under Windows
- AdaptiveAvgPool2D 不支持 onnx 导出,自定义一个类代替 AdaptiveAvgPool2D
- Global and Chinese market of amateur football helmets 2022-2028: Research Report on technology, participants, trends, market size and share
- Quantitative investment learning - Introduction to classic books
猜你喜欢
Hazelnut cloud - SMS (tool)
Which PHP open source works deserve attention
Nuxt. JS - learning notes
量化投资学习——经典书籍介绍
JS reverse | four libraries and one platform response data encryption
MySQL 10th job - View
nacos2.x.x启动报错信息Error creating bean with name ‘grpcClusterServer‘;
DataBinding使用与原理分析
MySQL第六次作业-查询数据-多条件
Opencv image processing - grayscale processing
随机推荐
MySQL第七次作业-更新数据
一键部署属于自己的社区论坛
Développeur, quelle est l'architecture des microservices?
【深度学习理论】(6) 循环神经网络 RNN
MySQL seventh job - update data
MySQL第八次作业
Expand and collapse too high div
Write data to local file
CentOS安装Redis多主多从集群
Easyx-----c语言实现2048
Notes - simple but adequate series_ KVM quick start
The fourteenth MySQL operation - e-mall project
Based on Zeng Shen's explanation, the line segment tree is studied again one
工作汇报(2)
Jasperreports - print PDF (project tool)
[echart] II. User manual and configuration item reading notes
一键部署ceph脚本
MySQL第九次作业-连接查询&子查询
Cereals Mall - Distributed Advanced
MySQL 12th job - Application of stored procedure