当前位置:网站首页>Ruiji takeout notes
Ruiji takeout notes
2022-07-04 14:18:00 【Fengyin Pro】
summary
Functional architecture
Database building, database building and table building
Table description
development environment
Maven build
Directly create a new project
Inherit the form of the parent project to do this , Create a new parent project here
pom file
server:
port: 9001
spring:
application:
name: ccTakeOut
datasource:
druid:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/ruiji?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowPublicKeyRetrieval=true
username: root
password: 333
redis:
host: localhost # Local IP or virtual machine IP
port: 6379
# password: root
database: 0 # By default 0 Number db
cache:
redis:
time-to-live: 1800000 # Set the expiration time of cached data ,30 minute
mybatis-plus:
configuration:
# When mapping entities or attributes , Remove the underscores from the table names and field names in the database , Turn on mapping according to hump nomenclature
map-underscore-to-camel-case: true
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
global-config:
db-config:
id-type: ASSIGN_ID
Start the test
Create a test class and start
Import the front page
Import
In the case of default page and foreground page , Drag these two directly to resource Direct access under the directory is not accessible , Because being mvc The framework intercepted
So we need to write a mapping class to release these resources
Create a configuration mapping class
Successful visit
The background and development
Database entity class mapping
use mybatis plus To realize reverse engineering
Here is the old version of Reverse Engineering
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.30</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.3.1</version>
</dependency>
<!--mybatis-plus The code generator depends on -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.3.2</version>
</dependency>
How to play depends on here
MP Reverse engineering course
Account operation
Landing function
Front page
database
Business logic
The comparison between the two strings here is useless != To achieve , Can only equals Then take the opposite to judge
Go straight to the code , There is no reference to service The operation of the layer
/** * @param request If the login succeeds, put the object into Session in , Convenient for subsequent taking * @param employee utilize @RequestBody Annotation to parse the data from the front end Json, At the same time, use objects to encapsulate * @return */
@PostMapping("/login")
public Result login(HttpServletRequest request, @RequestBody Employee employee) {
String password=employee.getPassword();
String username = employee.getUsername();
log.info(" land ");
//MD5 encryption
MD5Util md5Util = new MD5Util();
password=MD5Util.getMD5(password);
// Check the employee object through the account , Don't go here Service The layer
LambdaQueryWrapper<Employee> lambdaQueryWrapper = new LambdaQueryWrapper();
lambdaQueryWrapper.eq(Employee::getUsername, username);
Employee empResult=employeeService.getOne(lambdaQueryWrapper);
// Judge whether the user exists
if (!empResult.getUsername().equals(username)){
return Result.error(" Account does not exist ");
// Is the password correct
}else if (!empResult.getPassword().equals(password)){
return Result.error(" Wrong account password ");
// Whether the employee account status is normal ,1 Normal state ,0 Prohibition
}else if (empResult.getStatus()!=1){
return Result.error(" The current account is being blocked ");
// Login is allowed when the status is normal
}else {
log.info(" Landing successful , Account deposit session");
// staff id Deposit in session,
request.getSession().setAttribute("employ",empResult.getId());
return Result.success(" Landing successful ");
}
}
For specific code, please refer to the following path
com.cc.controller.EmployeeController
Exit function
Click to exit
Delete session object
/** * @param request Delete request scoped session object , Just press login request.getSession().setAttribute("employ",empResult.getId()); Delete employee Just go * @return */
@PostMapping("/logout")
public Result login(HttpServletRequest request) {
// Try to delete
try {
request.getSession().removeAttribute("employ");
}catch (Exception e){
// Delete failed
return Result.error(" Logout failed ");
}
return Result.success(" Log out successfully ");
}
Perfect login ( Add filter )
Here, the user directly url+ The resource name can be accessed casually , So we need to add an interceptor , When there is no login , No access , Automatically jump to the login page
Filter configuration class annotation @WebFilter(filterName=" Interceptor class name is lowercase ",urlPartten=“ The path to intercept , such as /*”)
Before judging the login status of users, it was saved session There's a name in it employee The object of , Then just look at this session Whether he is logging in or not is known
Be careful , If you want to save or get , You have to use them all HttpServletRequest
Object to get , other request Objects are not available
Here's a word
call Spring The string of the core package matches the object of the class , Match paths , And return the comparison result
If it is equal, it is true
public static final AntPathMatcher PATH_MATCHER = new AntPathMatcher();
The front-end interceptor finishes jumping to the landing page , Do not process at the back end
There's too much code , Give me a path , Go directly to Gitee see
request Of js Code path :resource/backend/js/request.js
The path of the interceptor :com.cc.filter.LoginCheckFilter
New employees
New employee function ,( The front end verifies the length of the mobile phone number and ID number )
request URL: http://localhost:9001/employee (POST request )
modified Employee Entity class , Universal id Snowflake auto increment algorithm to add id
Here we use service Interface inherited MybatisPlus The function of
It can be used after injection , Insert method
Basically, they are automatic CRUD, Access path :com.cc.controller.EmployeeController
Global exception handling
Take a look at this code first try catch
such try catch It's good to catch exceptions , however , A lot of code , Super much try catch It's going to be messy
So we need to add global exception handling , stay Common It's a bag , and Result At the same level , This is just an example , Incomplete
When the error message appears Duplicate entry when , It means that the new employees are abnormal
therefore , We make some small changes to the methods of exception classes , Make this abnormal feedback more humanized
Try the client again at this time , It will provide humanized error reporting , Very happy ~
This time, I'll go back to Controller, There is no need to come again try catch This is the form , Don't worry about him , Because once there is a mistake, it will be our AOP Capture . therefore , There is no need to use try catch Here we go
Exception class location :com.cc.common.GloableExceptionHandler
Paging query of employee information
Interface Analysis
It's a clich é about paging queries
demand
Paging request interface
Query employees and display interface
Logical process
Paging plug-in configuration class
To get a first MP Paging plug-in configuration class
The reason is and 3.2.3 Version of code generator conflicts
Paging plug-ins are popular solutions
Comment out
Add configuration class
Interface design
Front end considerations
page Inside object
It includes the use of query constructors
The specific details are under this package :com.cc.controller.EmployeeController.page
/** * The employee list interface is displayed in pages 、 Query an employee * @param page Look up the page * @param pageSize There are several pieces of data on each page * @param name Search for names =name The data of * @return return Page page */
@GetMapping("/page")
public Result<Page> page(int page, int pageSize,String name){
// Paging constructor ,Page( Page , Check a few )
Page pageInfo = new Page(page, pageSize);
// Query builder
LambdaQueryWrapper<Employee> lambdaQueryWrapper = new LambdaQueryWrapper();
// Filter conditions .like( Under what conditions are fuzzy queries enabled , Fuzzy query fields , The name that was vaguely interpolated )
lambdaQueryWrapper.like(!StringUtils.isEmpty(name), Employee::getName, name);
// Add sort
lambdaQueryWrapper.orderByDesc(Employee::getCreateTime);
// Query page 、 Auto update
employeeService.page(pageInfo, lambdaQueryWrapper);
// Return query results
return Result.success(pageInfo);
}
Enable 、 Disable employee account
Nothing more than modification status,0 Ban ,1 Enable
This kind of play method of Judging according to the landing characters , Is the front
The location of this page resource/backend/page/member/list.html
See what the object looks like , If it is admin,vue Of v-if The command will display the Edit button
If it is an ordinary user , Will hide the Edit button
Fix a little Bug
The Edit button is not displayed on the front end , stay localStorage No admin object
This value should not be login success , Should be Employee The object of Json
Guess it's when you land request The object stored in the file is not saved well
Just change it to object storage
It's all normal this time
Function writing
Review the
PutMapping yes Resultful Style of request
The current status is 1, Take the target state value directly ( The status changes to disabled ) updated
Id Precision loss ,js Unique bug, Deal directly with Long Can't handle , want Long turn String Go back to
Using object converters JacksonObjectMapper, Turn the object to Json
take Long Type Id Convert to String Data of type
stay MVC Extend a message converter in the configuration class
The test function is normal , Update employee status normally
Message extender configuration location :com.cc.common.JacksonObjectMapper
Object mapper location :com.cc.config.WebMvcConfig
Employee status update location :com.cc.controller.EmployeeController
Edit employee information
request API, This is the first request , Find out the user , Then fill in the page
You can see it , This kind of request is ResultFul Style of request
Use in the controller @PathVariable(“/{ Parameter name }”) Comments to receive
Perfect update
Update method location :com.cc.controller.EmployeeController.getEmployee
The public fields are automatically populated
Like some public fields , It makes no sense to fill it up repeatedly , Simplify the filling operation .
Take out this function , Carry it out alone for automatic filling
Annotate the entity class attributes @TableField(fill = Filling conditions )
Look at the source code .fill Is the filling condition , Enumerations are used for processing
Adding comments and conditions is not the end , Also add configuration classes for processing , Specify the filled data
stay common Create a custom class under the package , The key is to achieve MetaObjectHandler Under interface insertFill and updateFill
Confirm the fields required for filling . And I want to join @Component annotation , Leave this class to the framework to manage , Otherwise, it is easy to find ,setValue The value of will lock whether it needs to be updated according to the field name added in the annotation
Location :com.cc.common.MyMetaObjectHandler
But there's a problem , If I want to update the administrator field, it is very difficult , Because I can't get it here Request Scope object for , So we need to find a way to deal with .
This is the time ThreadLocal
To obtain objects , This thread runs through the whole run , You can get it through him
When using
What is the ThreadLocal
The key is coming.
This figure
My idea is when users log in , Put this id Put into , Wait until the field is filled , from ThreadLocal Take this resource out again .
Direct operation is not good , Package it into a tool class , The methods in this tool class are static , You can call... Directly through the class 、 And they are all static methods , To save and read
I choose Utils Create
For the first time Bug
The specific package is utils in , Yes Bug, Encapsulated classes ThreadLocal Data not available , I'm not sure why , Write this down for the time being
// be based on ThreadLocal Wrapper utility class , The user saves and obtains the currently logged in user id
// ThreadLocal Take thread as Scope , Save a copy of the data in each thread
public class BaseContext {
private static ThreadLocal<Long> threadLocal = new ThreadLocal<>();
// Set the current user id
public static void setCurrentId(Long id){
threadLocal.set(id);
}
public static Long getCurrentId(){
return threadLocal.get();
}
}
Be careful ,ThreadLocal Not a thread , Only the same thread can get , It's not something a thread can't get
Solution
change setId The location of , Store it inside the filter , Even a thread , Can get . But I have tried , It's really a thread , But I still can't get it .
Change the way of thinking : Because I want to take Request In the object Id Well , therefore , As long as there is Request Of id Just go , Don't be too persistent, you must use ThreadLocal Come and save , therefore , I choose to inject here HttpServletRequest Object to solve this problem .
Dishes page
Classification of dishes
The tables involved are classification tables category
The business process
New dish classification
The request mode is Post request
Controller position :com.cc.controller.CategoryController (save)
Show the dishes by category
Still those steps
- Create paging constructor Page pageInfo = new Page( Page , A few pieces of data per page );
- If you need conditional filtering, add conditional filter LambaQueryWarpper
- Injected service object ( Inherited MP Of BaseMapper Interface ) To call Page object
service object .page( Paging information , Conditional filter ) - Just return the result
Paging query location :com.cc.controller.CategoryController.page
Delete dish classification
Normal version , There is no consideration of the relevance of classification
Perfect it , If there are dishes under the current dish classification , You are not allowed to delete
So before deleting, you must make a judgment before deleting , Do not meet the conditions , We need to throw an exception to prompt
Because there is no class that returns exception information , Here we need to make a custom class that specially returns exception information CustomerException
The location of this class is also common It's a bag
Because we created a global exception handler before , Also use , Because we need to intercept exceptions for unified processing
still com.cc.common.GloableExceptionHandler
Handle exceptions thrown , You can provide target interception and exception notification for new exceptions
Delete dishes classified controller Interface in :com.cc.controller.CategoryController (delCategory)
Because of the special business , And relatively long , Just separate and put the business in service It's a bag
service Interface location :com.cc.service.impl.CategoryServiceImpl (removeCategory)
Modify package information
Very simple CRUD, Call directly MP Just update it
API Location
com.cc.controller.CategoryController (updateCategory)
File upload download ( a key )
Upload logic
First contact with upload and download functions
File upload logic ( Back end )
Parameter name is required
The type of file received must be Method name (MultipartFile The name of the file uploaded by the front end )
Therefore, the receiving name of the backend must also be changed to file
Upload logic implementation
The specific storage path is written in the configuration file
use @Value Just inject it into the business
The specific location is com.cc.controller.CommonController (upLoadFile)
Download logic
Picture echo function
Input and output streams are used
Location :com.cc.controller.CommonController (fileDownload)
Menu management page
New dishes
Demand analysis
The involved table is dish and dish_flavor
Development logic
New implementation
Because it is a multi table operation ,MP You can't do it directly , So put service Layers are extracted for processing
also , Because it involves two tables , There are also transactions to control , Prevent multi table operation from crashing
Multiple table operations can only be performed one by one ,MP There is no way to operate multiple tables at once
Because it involves multiple tables , So we need to add annotations to deal with transactions
@Transactional Open transaction
@EnableTransactionManagement Add... In the startup class , Support transaction startup
Controller Location :com.cc.controller.DishController (addDish)
Service Location :com.cc.service.DishService
ServiceImpl Location :com.cc.service.impl.DishServiceImpl (addDishWithFlavor)
New dishes to get the types of dishes
Receive one from the front end type=1 The annotation , The purpose is in the classification table , The classification of dishes is 1, The package classification is 2, Distinguish the two , Get all types of dishes
Location :com.cc.controller.CategoryController (listCategory)
Dish sorting
I also made the dishes in different pages , Don't write too much , Position in :com.cc.controller.CategoryController (dishPage)
Record a knowledge point , If there is no class on the back end corresponding to the data on the front end , Then you can encapsulate a class to encapsulate the data required by the front end
DTO object
This class can extend some entity classes , Inherit from a parent class , Add some more
such as Dish and DishDto
DishDto Inherit from Dish class , And on this basis, it is extended
Update dish information
That's it. update
Logic
Be careful , The echo data here is to use DishDto, Because the front end should display information such as taste , If you use Dish It cannot be displayed perfectly , So want to use DishDto
Echo fill query
besides , This is a multi table joint query , use MP Definitely not , I have to write it myself
Controller Location :com.cc.controller.DishController (updateDish)
Service Location :com.cc.service.DishService
ServiceImpl Location :com.cc.service.impl.DishServiceImpl
Update implementation
In fact, it is the simultaneous update and deletion of two tables , therefore MP Direct operation is not allowed , So we need to Service The layer itself encapsulates a deletion method , to Controller Just delete the layer call
about Dish Objects can be updated directly , because DishDto yes Dish Subclasses of
So you can call DishService Of update Methods the incoming DishDto object , To achieve Dish Update
Controller Location :com.cc.controller.DishController (updateDish)
It's really the same as the one above , Because the way of request is different
Service Location :com.cc.service.DishService
ServiceImpl Location :com.cc.service.impl.DishServiceImpl (updateDishWithFlavor)
Other features
Complete the development of some small functions
Stop selling function
That is to put the database status Update the value , Two paths , One for sale , One stop
Stop selling request path
If the state is different , It will change from stop selling to start selling , At the same time, the corresponding request path is also different
Controller Location :com.cc.controller.DishController (updateStatusStop)
stop it
Controller Location :com.cc.controller.DishController (updateStatusStart)
start-up
Delete function
Dish deletion function
Complete logical deletion , Not really delete
Location :
Controller Location :com.cc.controller.DishController (deleteDish)
stop it
Package page
It's actually a collection of dishes
Overview of new packages
Database involved
Import SetmealDto
Add the menu of the set menu
Controller Location :com.cc.controller.DishController (listCategory)
The new package realizes
It's similar to the new dishes , Here is also the operation of multiple tables
Controller Location :com.cc.controller.SetmealController (saveSetmeal)
Service Location :com.cc.service.SetmealService
ServiceImpl Location :com.cc.service.impl.SetmealServiceImpl(saveWithDish)
Package paging
The pagination of the package here is different from that in the past , Design to multi table content
Package paging Controller Location :com.cc.controller.SetmealController.pageList
package Mapper Interface location :com.cc.mapper.SetmealMapper
Mapper file location :resource.mapper.SetmealMapper
Update package
Adding packages and updating packages are almost identical , The fields of barabara are the same
But notice , Modify the package , You need to fill in the dishes page first , This page needs to be filled with the information of the dishes to be modified .
First request , A see be Restful Style request
Get the package Controller Location :com.cc.controller.SetmealController.getSetmal
Update sales status
It is very similar to the previous business logic , I don't want to go into details , Put it directly at the interface
Controller Location :com.cc.controller.SetmealController (startSale/stopSale)
Delete package
It can be deleted separately , You can also delete in batch , The interface is all gold , Can connect , It mainly depends on the data transmitted
Interface
== Multi table delete , stay Controller Direct implementation is not realistic , So we need to Service Write the business well ==
Controller Location :com.cc.controller.SetmealController (deleteSetmeal)
Service Location :com.cc.service.SetmealService
ServiceImpl Location :com.cc.service.impl.SetmealServiceImpl(removeWithDish)
The front desk development ( Mobile terminal )
Account login
Text messaging
Alibaba cloud SMS service tutorial
Code implementation
Official document address
Import Maven
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-core</artifactId>
<version>4.5.16</version>
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-dysmsapi</artifactId>
<version>1.1.0</version>
</dependency>
Import the tool class of SMS login , hold ACCESSKeyID and Secret Just replace it in place
Verification code sending
Data model user surface , A special table for mobile phone verification code
Development process
Modify interceptor , Release operation
controller Location :com.cc.controller.UserController (sendMsg)
After sending, you need to verify , Verification is another login 了
The user login
controller Location :com.cc.controller.UserController (login)
Login here also involves the function of filter release , Don't forget , Put the user id Deposit in session, The filter will be validated
filter
controller
Foreground page
Import user address book
Address table
Here you can import the ready-made AddressBookController, I didn't write it myself
com.cc.controller.AddressBookController
Food display
Logical combing
modify DishController Of list Method , To meet the requirements of the front desk request
controller Location :com.cc.controller.DishController (listCategory)
Set menu dishes Controller:com.cc.controller.SetmealController (list)
The shopping cart
Add the dishes to the shopping cart
Logical combing
Be careful , There is no need for the back end to calculate the total price , It's the unit price * Quantity of this operation , Not the content of the back end . The front end calculates by itself when it is displayed .
Location :com.cc.controller.ShoppingCartController (add)
Place an order
The corresponding two tables , One is orders surface , The other is orders_detail surface
orders surface
orders_detail surface
Interaction process
The business is more complex , stay Service It's written in English com.cc.service.impl.OrdersServiceImpl
So far, the basic part is completed , Start optimizing project performance
Summary of small knowledge points
@RequestBody Use
Only the parameter passed is Json Ability to use RequestBody receive , If not Json The situation of ( Like that ?key=value&key=value) It can't be used , Meeting 400 error
About RequestBody When to use
Cache optimization
be based on Redis Cache optimization
Environment building
Redis To configure
Join in Pom file
<!-- Import Redis rely on -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
Join in Redis Configuration class
@Configuration
public class RedisConfig extends CachingConfigurerSupport {
@Bean
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
// default Key The serializer is :JdkSerializationRedisSerializer
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setConnectionFactory(connectionFactory);
return redisTemplate;
}
}
yml Add configuration
SMS verification code 、 Login optimization
Add valid time verification to the verification code , Set the effective time of SMS verification code
If the login is successful , Automatically delete the verification code in the cache
Optimize the location :com.cc.controller.UserController sendMsg and login
Inject RedisTemplete
Optimize the verification code
Optimize after login
login In the method
The filter here should also be changed , Because of the login id Data from session Turned into redis Deposit , Therefore, the relevant parts of the filter should be transformed
com.cc.filter.LoginCheckFilter
It is also necessary to inject RedisTemplate
Cache the foreground dish data
Cache ideas , Ensure that the cache database and DBMS Keep the data in sync , Avoid reading dirty data ( No updated data )
Yes DishController To optimize , Added cache
Visit again to find , If the current dish classification has been cached , You won't check the database anymore
Update the dishes and update the cache
Ensure less dirty data , So add clean cache , If it is not cleaned in time , Save the new data , The list database cannot be updated synchronously . There will be problems .
Here we clean up the precise data . Large area cache clearing is also more performance intensive
This is full cleaning
This is precision cleaning
SpringCache
brief introduction
SpringCache Common annotations and functions
Fast start
Add... To the startup class @EnableCaching
annotation , Enable caching framework
@CachePut annotation
Cache method return value , Cache one or more pieces of data
@CacheEvict annotation
Delete cache
@Cacheable annotation
Have a look first Spring Whether the current data has been cached , If it has been cached, return directly .
If there is no cache, cache it directly into memory
Some special circumstances ,condition Properties and Unless attribute
The front is used SpringCache Built in cache container , Performance is definitely not comparable Redis
So now start introducing Redis As SpringCache Cached products
Switch to a Redis As a cache product
SpringCache-Redis
Import jar package
Inject the corresponding cache product Manager That's all right. , Here we use RedisManager For example
utilize SpringCache-Redis To cache package data
Add... To the startup class @EnableCaching
annotation , Enable caching framework
Pit when adding notes
Here is equivalent to from Return Get in the Setmeal Properties in , however Return When the data is Result Packaged Setmeal data , Obviously, serialization cannot be completed , Here also need to be right Result Class to serialize
Inherit serialization class , Make it serializable
= At this point, the optimization of the cache is completed , At this time, if there is current value Cache of names , It will automatically return to , If not, just check . The current cache expires automatically at yml There are detailed configurations
Save package method cache optimization
1. Save the package , The corresponding cache must be deleted , Because the data is updated, it needs to be retrieved
There are also updated packages , For the same reason
The deletion method needs to add
The preservation method should also be added
Database optimization
MySQL Read / write separation
Change the single point database into a distributed database server
Write and read .
MySQL Master and slave copy build
Master database settings
Master slave replication architecture diagram
The above can achieve the synchronization of master database data and slave database data
Configure the main library
Linux Reform the law
log-bin=mysql-bin # Start binary
server-id=100 # only id
windows Reform the law
stay mysql Under installation path
After modification, restart MySQL
windows The restart tutorial of version is here
restart mysql
=======================================================
GRANT REPLICATION SLAVE ON*.*to'xiaoming'@'%'identified by '[email protected]';
Here I put the local MySQL As a host , Take Alibaba cloud as a slave
Run the permission SQL
Check the host status show master status;
From library settings
Select Alibaba cloud from the Library
Or modify the configuration file first , Join the port id
The second step is to restart from the Library (Linux in )
Third parts , Set up connection to the host
function SQL
Run it
Specifically, you can use the slave show master status see
change master to master_host='ip',master_user='xiaoming',master_password='[email protected]',master_log_file='mysql-bin.eo0001',master_log_pos= The host position
Here I have two servers , a docker Installed mysql( Slave )
The other one is normally installed mysql Be the host , There are many problems in the configuration process , Refer to the following link
Reference tutorial
Be sure to remember to start the slave after the above slave connection command runs successfully, that is
slave start
Last run start slave
Even if the implementation is successful
Check the slave status
show slave status
In this way, it will be built
test
Even if the construction is completed here
Problems encountered
The problem here , Not even
Want to be a local host , It doesn't seem very good to be a slave on the Internet , I got another server to do read-write separation
After getting the slave , Start configuration , install MySQL wait
Sometimes it will prompt io Conflict , This is because the previous slave was not shut down , Just close it stop slave
once It's ready to run
A slave boot command was forgotten , Changed all night
If you do not run the slave boot, it will become like this
Write mainly and read practically
summary
How hard is it to decide SQL Which library should be assigned , It depends on Sharding-jdbc Framework to separate read and write processing
actual combat
Steps are as follows
Import Maven coordinate
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-jdbc-spring-boot-starter</artifactId>
<version>4.0.0-RC1</version>
</dependency>
To configure yml file
spring:
application:
name: ccTakeOut
shardingsphere:
datasource:
names:
master,slave
# Main library ( Add, delete and change operation )
master:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://121.89.200.204:3306/ruiji?characterEncoding=utf-8
username: root
password: 333
# From a data source ( Read operations )
slave:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://121.36.51.170:3306/ruiji?characterEncoding=utf-8
username: root
password: 333
masterslave:
# Read write separation configuration
load-balance-algorithm-type: round_robin # polling ( If there are multiple slave libraries, they will poll for reading )
# The final data source name
name: dataSource
# Main database data source name
master-data-source-name: master
# From the list of library data source names , Multiple commas separate
slave-data-source-names: slave
props:
sql:
show: true # Turn on SQL Show , Default false
main:
allow-bean-definition-overriding: true # allow bean Data source coverage
Read about the yml To configure
allow Bean Defining coverage is important
test
Start project , You can see , The read and write operations have reached different hosts
Read-write separation test
Nginx Deploy
Separate front and rear development
Development process
YApi
Swagger( Commonly used )
Its main function is to help backend personnel generate backend interface documents
Usage mode
Import coordinates
<!--knife4j Interface management -->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
<version>3.0.2</version>
</dependency>
Import configuration class
Specific configuration location com.cc.config.WebMvcConfig
Start the service , Access path +doc.html
After entering, you can manage the existing interfaces
Swagger Commonly used annotations
The directly generated annotation content is not very perfect
Swagger Commonly used annotations
Take entity classes as an example
Controller The annotations on
The above are examples , Finally perfect the annotation , Documents will be better used , A more detailed .
Project deployment
front end
Front end as a project , You also need to pack , Packed as dist Catalog
Put this dist Catalog , Thrown into Nginx in HTML Folders will do , That is, the static resource
It's not over when you pass it on , We need to configure it well
One is static resources , The other is reverse proxy
Static resource allocation
First configure static resources
Request agent configuration
restart Nginx, Test it , visit .
Any request can see , With a prefix
The port given by the backend project is 9001
The request path is :http://www.ccsmile.fun:9001/api/employee/login
We don't have this on the back end api The prefix of
By rewriting url, You can put the http://www.ccsmile.fun:9001/api/employee/login
become http://www.ccsmile.fun:9001/employee/login
Request address of , This completes the request proxy forwarding operation
The configuration file is as follows
server{
listen 80;
server_name localhost;
# Static resource allocation
location /{
root html/dist;
index index.html;
}
# Request forwarding agent , rewrite URL+ forward
location ^~ /api/{
rewrite ^/api/(.*)$ /$1 break;
proxy_pass http:// The back-end service ip: Port number ;
}
# other
error_page 500 502 503 504 /50x.html;
location = /50x.html{
root html;
}
}
Last save the file , restart Nginx, The configuration is complete
But I still don't know why it's not easy to use , It still needs to be solved , If not, just add the receive request prefix to the backend
Back end
Upload script , Automatically pull the latest script
In this way, on the development side and Linux The end passes Gitee Indirectly realize synchronization
The script content
#!/bin/sh
echo =================================
echo The automated deployment script starts
echo =================================
echo Stop the original running project
APP_NAME=reggie_take_out
tpid=`ps -ef|grep $APP_NAME|grep -v grep|grep -v kill|awk '{print $2}'`
if [ ${tpid} ]; then
echo 'Stop Process...'
kill -15 $tpid
fi
sleep 2
tpid=`ps -ef|grep $APP_NAME|grep -v grep|grep -v kill|awk '{print $2}'`
if [ ${tpid} ]; then
echo 'Kill Process!'
kill -9 $tpid
else
echo 'Stop Success!'
fi
echo Ready to go from Git The warehouse pulls the latest code
cd /usr/local/javaapp/reggie_take_out
echo Start from Git The warehouse pulls the latest code
git pull
echo Code pull complete
echo Start packing
output=`mvn clean package -Dmaven.test.skip=true`
cd target
echo Start project
nohup java -jar reggie_take_out-1.0-SNAPSHOT.jar &> reggie_take_out.log &
echo Project start up complete
Execute the script OK 了
Remember to revise yml Part of the document , Such as file path and other information ~
It's over and flowers are scattered
边栏推荐
- China Post technology rushes to the scientific innovation board: the annual revenue is 2.058 billion, and the postal group is the major shareholder
- 程序员的焦虑
- JVM memory layout detailed, illustrated, well written!
- Error in find command: paths must precede expression (turn)
- 卷积神经网络经典论文集合(深度学习分类篇)
- How to package QT and share exe
- LifeCycle
- go语言中的文件创建,写入,读取,删除(转)
- Install and use MAC redis, connect to remote server redis
- Understand chisel language thoroughly 03. Write to the developer of Verilog to chisel (you can also see it without Verilog Foundation)
猜你喜欢
TestSuite and testrunner in unittest
[R language data science]: cross validation and looking back
Why should Base64 encoding be used for image transmission
Yingshi Ruida rushes to the scientific and Technological Innovation Board: the annual revenue is 450million and the proposed fund-raising is 979million
Unity Shader学习(三)试着绘制一个圆
[antd] how to set antd in form There is input in item Get input when gourp Value of each input of gourp
Excel quickly merges multiple rows of data
Test evaluation of software testing
China Post technology rushes to the scientific innovation board: the annual revenue is 2.058 billion, and the postal group is the major shareholder
MySQL之详解索引
随机推荐
Use the default route as the route to the Internet
QT how to detect whether the mouse is on a control
China Post technology rushes to the scientific innovation board: the annual revenue is 2.058 billion, and the postal group is the major shareholder
Applet live + e-commerce, if you want to be a new retail e-commerce, use it!
1200. Minimum absolute difference
富文本编辑:wangEditor使用教程
吃透Chisel语言.04.Chisel基础(一)——信号类型和常量
自主工业软件的创新与发展
Understand chisel language thoroughly 04. Chisel Foundation (I) - signal type and constant
Apple 5g chip research and development failure: continue to rely on Qualcomm, but also worry about being prosecuted?
sql优化之explain
Huahao Zhongtian rushes to the scientific and Technological Innovation Board: the annual loss is 280million, and it is proposed to raise 1.5 billion. Beida pharmaceutical is a shareholder
MongoDB常用28条查询语句(转)
[R language data science]: cross validation and looking back
IP lab monthly resumption · issue 5
Deming Lee listed on Shenzhen Stock Exchange: the market value is 3.1 billion, which is the husband and wife of Li Hu and Tian Hua
qt 怎么检测鼠标在不在某个控件上
LifeCycle
学习项目是自己找的,成长机会是自己创造的
吃透Chisel语言.06.Chisel基础(三)——寄存器和计数器