Articles Catalogue
- Project introduction
- system architecture
- Project module
- Application Technology Points
- Dubbox Distributed Service Framework
- Front-end framework Angular JS
- Spring Security
- FastDFS
- Redis
- Application in Home Page Advertising
- Application in Search
- Application in Registration
- Application in shopping cart
- Solr Server
- Freemarker
- Message Middleware ActiveMQ
- CAS Single Sign-on
- business
- Operator Business
- Bread crumb navigation
- Commodity Input
- Generating SKU List
- Search Service
- Shopping Cart
- Sweep Payment
- Other technical points
Project introduction
Mall online mall is a comprehensive B2B2C platform, similar to Jingdong Mall and Tianmao Mall. The website adopts the mode of merchants'residence. The merchants submit applications on the platform, and have the platform for qualification audit. After the approval, the merchants have independent management background to input commodity information. Commodities can be released after platform auditing. Mall online mall is mainly divided into three subsystems: website front-end, operator back-end and business management back-end.
- The front desk of the website mainly includes business functions such as website home page (advertisement), business home page, commodity detail page, search page, membership center, order and payment related page, secondkill channel and so on.
- Operator background mainly includes business auditing, brand management, specification management, template management, commodity classification management, commodity auditing, advertising type management, advertising management, order inquiry, business settlement and other business functions.
- Business management includes the function of goods on shelves.
system architecture
SOA architecture (back-end framework using Spring + Spring MVC + mybatis + Dubbox. The front end uses angular JS + Bootstrap.)
Architecture:
Project module
The project includes the following modules:
- mall-parent (aggregation engineering)
- mall-pojo (Universal Entity Class Layer)
- mall-dao (Universal Data Access Layer)
- mall-common
- mall-sellergoods-interface
- mall-sellergoods-service
- mall-sellergoods-web (operator management system)
- mall-shop-web (business management system)
- mall-content-interface (advertising service interface)
- mall-content-service (advertising service)
- mall-portal-web (portal)
- mall-solr-util (search import tool)
- mall-search-service (commodity search service interface)
- mall-search-service
- mall-search-web (commodity search)
- mall-page-interface (page static service interface)
- mall-page-service
- mall-page-web (static page)
- itcast_sms
- pinnyougou-user-interface (user service interface)
- pinnyougou-user-web (User Center Service)
- pinnyougou-user-web (user center)
- mall-cart-interface (shopping Cart Service interface)
- mall-cart-service
- mall-cart-web (shopping cart)
- mall-order-interface (order service interface)
- mall-order-service
- mall-order-web (order system)
- mall-seckill-interface (seckill service interface)
- mall-seckill-service
- mall-seckill-web
- mall-task-service
Dependency between services:
Application Technology Points
Dubbox Distributed Service Framework
Dubbox is a RPC-based distributed service framework for remote service invocation.
The zookeeper registry is officially recommended. Registry is responsible for the registration and search of service addresses, which is equivalent to directory services. Service providers and consumers only interact with the registry at startup. The registry does not forward requests and has less pressure.
After introducing dependencies through Maven, dubbo configuration can be introduced into Spring configuration file:
<!-- Quote dubbo service --> <dubbo:application name="mall-shop-web" /> <dubbo:registry address="zookeeper://192.168.25.132:2181"/> <dubbo:annotation package="com.mall.shop.controller" />
Front-end framework Angular JS
Angular JS is an excellent front-end JS framework. Angular JS has many characteristics, the core of which are MVC, modularization, automatic two-way data binding, dependency injection and so on.
Asynchronous requests can be easily made:
<script src="angular.min.js"></script> <script> var app=angular.module('myApp',[]); //A module called myApp is defined. //Define Controller app.controller('myController',function($scope,$http){ $scope.findAll=function(){ $http.get('data.json').success( function(response){ $scope.list=response; } ); } }); </script>
Spring Security
Spring Security is a security framework that can provide declarative secure access control solutions for Spring-based enterprise applications.
Create spring configuration file spring-security.xml
<!-- The following pages are not blocked --> <http pattern="/login.html" security="none"></http> <http pattern="/login_error.html" security="none"></http> <!-- Page Interception Rules --> <http use-expressions="false"> <intercept-url pattern="/*" access="ROLE_USER" /> <form-login login-page="/login.html" default-target-url="/index.html" authentication-failure-url="/login_error.html"/> <csrf disabled="true"/> </http>
FastDFS
FastDFS is an open source distributed file system written in C language. FastDFS is customized for the Internet. It fully considers the mechanism of redundant backup, load balancing, linear expansion, and pays attention to high availability, high performance and other indicators. Using FastDFS, it is easy to build a high-performance file server cluster to provide file upload and download services.
The file uploaded by the client is finally stored on the Storage server. After uploading the file, FastDFS will return its file ID in the storage server:
group1/M00/00/00/wKgZhVkMP4KAZEy-AAA-tCf93Fo973.jpg
Redis
Application in Home Page Advertising
Home page is visited by a large number of people every day, which causes great pressure on database access, even paralysis. Front page data can be stored in Redis to speed up access and reduce database pressure.
First try to extract the data from Redis, if it does not exist in Redis, then extract it from MySQL database and put it into Redis.
@Override public List<TbContent> findByCategoryId(Long categoryId) { List<TbContent> list = (List<TbContent>) redisTemplate.boundHashOps("content").get(categoryId); if (list == null) { System.out.println("Query the data from the database and put it in the cache "); TbContentExample example = new TbContentExample(); Criteria criteria = example.createCriteria(); criteria.andCategoryIdEqualTo(categoryId);//Specified condition: Classification ID criteria.andStatusEqualTo("1");//Designated condition: valid example.setOrderByClause("sort_order");//sort list = contentMapper.selectByExample(example); redisTemplate.boundHashOps("content").put(categoryId, list);//Put in the cache } else { System.out.println("Query data from the cache "); } return list; }
Application in Search
In order to improve the query speed, the brand and specification data of the query panel are put into Redis in advance.
Application in Registration
Click on the "Get Short Message Verification Code" link on the page to pass the phone number to the back end. The back end generates 6 digits randomly as SMS authentication code, saves them in Redis (mobile phone number as key), and sends them to the SMS gateway. When the user registers, the back end inquires whether the authentication code in Redis is the same as the authentication code filled in by the user according to the mobile phone number. If it is different, it prompts the user not to register.
Application in shopping cart
In the case of user login, the merchandise information of shopping cart is put into Redis, with username as key and shopping cart list as value.
Solr Server
The difference between Elastic search and Solr
Background: They are all developed on the basis of Lucene search server, an excellent, high-performance enterprise search server. The reason for high performance is the inverted index based on word segmentation technology.
Development languages: they are all based on java language
Birth date: Solr(2004), Elastic search (2010, update, more powerful)
Difference:
- When indexing in real time, Solr will generate io blocking, while es will not, and ES query performance is higher than solr.
- When adding data dynamically, the retrieval rate of solr will slow down, but es will not change.
- Solr uses zookeeper for distributed management, es itself has distributed system management function.
- Solr is usually deployed on Web servers, such as tomcat. Solr is a dynamic web project in nature.
- Solr supports more formatted data (xml,json,csv, etc.), while es only supports JSON file format.
- Solr is a powerful solution for traditional search, but es is more suitable for emerging real-time search applications.
- Solr's official website provides more functions, while es itself focuses more on core functions.
The domain in Solr is equivalent to the table field in the database. Users store data. Therefore, users define related fields according to business needs. Generally speaking, each kind of field corresponds to one kind of data, and users operate the same kind of data. Modify the schema.xml file of solrhome and set up the business system Field. The key of configuration is:
indexed: indexed or not
Storage: Storage or not
The role of replication domain is to replicate data from one Field into another domain for joint search:
<field name="item_keywords" type="text_ik" indexed="true" stored="false" multiValued="true"/> <copyField source="item_title" dest="item_keywords"/> <copyField source="item_category" dest="item_keywords"/> <copyField source="item_seller" dest="item_keywords"/> <copyField source="item_brand" dest="item_keywords"/>
Freemarker
Freemarker: Static Web Page Technology
Web static technology and caching technology all have the same point in order to alleviate the pressure of database access, but the specific application scenarios are different, caching is more suitable for small-scale data, while Web static is more suitable for large-scale and relatively less frequently changing data. In addition, webpage static is also conducive to SEO.
FreeMarker is a template engine written in Java language, which generates text output based on templates. FreeMarker has nothing to do with Web containers, that is, when the Web runs, it does not know about Servlet s or HTTP. It can be used not only as an implementation technology of the presentation layer, but also to generate XML, JSP or Java.
Step 1: Create template files
There are four elements in the template file:
- Text, part of direct output
- Annotations, that is <# -... Format will not output
- Interpolation: that is, ${ } Partially, the output will be replaced by a portion of the data model
- FTL instructions: FreeMarker instructions, similar to HTML tags, are distinguished by # before the name, and will not be output.
Step 2: Generating static pages
//1. Create configuration classes Configuration configuration=new Configuration(Configuration.getVersion()); //2. Setting the directory where the template is located configuration.setDirectoryForTemplateLoading(new File("D:/pinyougou_work/freemarkerDemo/src/main/resources/")); //3. Setting Character Set configuration.setDefaultEncoding("utf-8"); //4. Loading Template Template template = configuration.getTemplate("test.ftl"); //5. Create a data model Map map=new HashMap(); map.put("name", "Zhang San "); map.put("message", "Welcome to the magical world of premium shopping!"); //6. Create Writer Objects Writer out =new FileWriter(new File("d:\\test.html")); //7. Output template.process(map, out); //8. Close the Writer object out.close();
Message Middleware ActiveMQ
By introducing the message middleware activeMQ, the operator system is decoupled from search service and page generation service.
ActiveMQ has two types of messaging:
- One is point-to-point, that is, a producer and a consumer correspond one by one.
- The other is the publish/subscribe mode, in which a producer generates messages and sends them, which can be received by multiple consumers.
When ActiveMQ is integrated with Spring, JmsTemplate can be used to manipulate message queues.
-
The message middleware ActiveMQ is used to realize zero coupling between the operator's background and search service. After the operator carries out commodity audit, it sends a message (SKU list) to ActiveMQ, and the search service receives the message from ActiveMQ and imports it into the solr index library. It can decouple the search service from the operator control layer.
-
The message middleware ActiveMQ is used to realize zero coupling between the backstage of the operator and the web page generation service. The operator sends a message (commodity ID) to ActiveMQ after performing commodity audit, and the Web page generation service performs the Web page generation operation after receiving the message from ActiveMQ.
-
ActiveMQ is used to send registered short messages, which is carried out by a special short message sending module (Ali greater).
CAS Single Sign-on
Single Sign On (SSO) is one of the most popular solutions for business integration. SSO is defined as an application system in which users can access all trusted applications with only one login.
In user pages, CAS and Spring Security are integrated, with different responsibilities:
- CAS: Login Authentication (Single Sign-on) means login under the current project. Other projects that trust each other can automatically authenticate whether they have logged in or not.
- Spring Security: Privilege management (to determine which resources an administrator or ordinary user can access for the currently logged-in user)
After the login process of CAS, CAS will give the user name of the login user to Spring Security framework, which is responsible for determining which access rights the current user has.
business
Operator Business
Addition, deletion and modification of brands, specifications and templates
Business audits, commodity audits, etc.
Advertising type and advertising entry.
Bread crumb navigation
You can jump to different levels by clicking on the breadcrumbs navigation bar.
//Level setting $scope.setGrade = function (value) { $scope.grade = value; } $scope.selectList = function (p_entity) { if ($scope.grade == 1) {//If level 1 $scope.entity_1 = null; $scope.entity_2 = null; } if ($scope.grade == 2) {//If Level 2 $scope.entity_1 = p_entity; $scope.entity_2 = null; } if ($scope.grade == 3) {//If Level 3 $scope.entity_2 = p_entity; } $scope.findByParentId(p_entity.id); //Query this subordinate list }
Bind breadcrumbs:
<ol class="breadcrumb"> <li><a href="#" ng-click="grade=1;selectList({id:0})">Top-level Category List</a></li> <li><a href="#" ng-click="grade=2;selectList(entity_1)">{{entity_1.name}}</a></li> <li><a href="#" ng-click="grade=3;selectList(entity_2)">{{entity_2.name}}</a></li> </ol>
Commodity Input
The difficulty of merchandise entry is uploading pictures and using FatDFS for file storage.
Front-end service layer:
app.service('uploadService',function ($http) { this.uploadFile = function () { var formdata = new FormData(); formdata.append('file',file.files[0]); return $http({ url:'../upload.do', method:'post', data:formdata, headers:{'Content-Type':undefined}, transformRequest: angular.identity }); } })
Backend:
@RequestMapping("/upload") public Result upload(MultipartFile file) { //get files String originalFilename = file.getOriginalFilename(); //Get the extension String extNmae = originalFilename.substring(originalFilename.lastIndexOf(".") + 1); try { FastDFSClient client = new FastDFSClient("classpath:config/fdfs_client.conf"); String fileId = client.uploadFile(file.getBytes(), extNmae); String url = FILE_SERVER_URL + fileId;//Picture full address return new Result(true,url); } catch (Exception e) { e.printStackTrace(); return new Result(false, "Upload failure"); } }
Three-level Classification of Commodities Selection Box:
Similar to the common linkage between provinces and municipalities in js, it is more convenient to implement through Angular JS ($watch method is used to monitor the value of a variable, when the monitored value changes, the corresponding function is automatically executed).
Generating SKU List
Click on the specifications above, and the table below will be generated automatically!
Triple loops generate the list:
//Create SKU List $scope.createItemList=function(){ $scope.entity.itemList=[{spec:{},price:0,num:99999,status:'0',isDefault:'0' } ];//initial var items= $scope.entity.goodsDesc.specificationItems; for(var i=0;i< items.length;i++){ $scope.entity.itemList = addColumn( $scope.entity.itemList,items[i].attributeName,items[i].attributeValue ); } } //Add column values addColumn=function(list,columnName,conlumnValues){ var newList=[];//New set for(var i=0;i<list.length;i++){ var oldRow= list[i]; for(var j=0;j<conlumnValues.length;j++){ var newRow= JSON.parse( JSON.stringify( oldRow ) );//Deep cloning newRow.spec[columnName]=conlumnValues[j]; newList.push(newRow); } } return newList; }
Search Service
Using Spring Data Solr to implement the search operation:
@Service(timeout=3000) public class ItemSearchServiceImpl implements ItemSearchService{ @Autowired private SolrTemplate solrTemplate; @Override public Map<String, Object> search(Map searchMap) { Map<String,Object> map=new HashMap<>(); Query query=new SimpleQuery(); //Adding query conditions Criteria criteria=new Criteria("item_keywords").is(searchMap.get("keywords")); query.addCriteria(criteria); ScoredPage<TbItem> page = solrTemplate.queryForPage(query, TbItem.class); map.put("rows", page.getContent()); return map; } }
Search results highlight:
Adding highlighting conditions directly to Criteria conditions requires setting highlighting prefixes and suffixes on the content to be highlighted:
<em style='color:red'></em>
private Map searchList(Map searchMap){ Map map=new HashMap(); //Highlighting effect settings HighlightQuery query=new SimpleHighlightQuery(); HighlightOptions highlightOptions=new HighlightOptions().addField("item_title");//Set the Highlighted Domain highlightOptions.setSimplePrefix("<em style='color:red'>");//Highlighted prefix highlightOptions.setSimplePostfix("</em>");//Highlighted suffix query.setHighlightOptions(highlightOptions);//Setting Highlight Options //Query by keyword Criteria criteria=new Criteria("item_keywords").is(searchMap.get("keywords")); query.addCriteria(criteria); HighlightPage<TbItem> page = solrTemplate.queryForHighlightPage(query, TbItem.class); //Get results for(HighlightEntry<TbItem> h: page.getHighlighted()){//Loop highlight entrance set TbItem item = h.getEntity();//Getting the primitive entity class if(h.getHighlights().size()>0 && h.getHighlights().get(0).getSnipplets().size()>0){ item.setTitle(h.getHighlights().get(0).getSnipplets().get(0));//Set highlighted results } } map.put("rows",page.getContent()); return map; }
The search panel has conditions such as commodity classification, brand, specifications and price range.
The business processes are as follows:
(1) When a user enters a keyword search, besides displaying the results of the list, he should also show what commodity categories the records searched by this keyword have.
(2) Query the corresponding template according to the first commodity classification, and query the brand list according to the template.
(3) Query the corresponding template according to the first commodity classification, and query the list of specifications according to the template.
(4) When the user clicks on the commodity classification of the search panel, the results of the classification are filtered based on the query results of the keyword.
(5) When the user clicks on the brand of the search panel, the results of screening the brand are displayed on the basis of the above results.
(6) When the user clicks on the specifications of the search panel, the results of the specifications are screened on the basis of the above results.
(7) When the user clicks on the price range, the results are displayed on the basis of the above results and screened according to the price.
(8) When the user clicks on the corresponding conditions of the search panel, hide the clicked conditions.
The execution process is as follows:
private Map searchList(Map searchMap){ ..... //1.1 Keyword Query ..... //1.2 Screening by Classification ..... //1.3 Screening by Brand ..... //1.4 Filtration Specification ..... //1.5 Screening by Price ...... //1.6 Paging Query ...... //1.7 Sort ...... //1.8 highlight processing ...... }
Specific Implementation Point This Connection
Shopping Cart
When the customer is not logged in: add the added goods to Cookies;
In the case of user login: store shopping cart data in Redis;
If a shopping cart exists in Cookies when a user logs in, it is necessary to merge the shopping cart of Cookies into Redis for storage.
The process of adding goods to the shopping cart:
- Query SKU commodity information according to commodity SKU ID;
- Get the business ID;
- Judging whether there is a shopping cart in the shopping cart list according to the business ID;
- If there is no shopping cart in the shopping cart list, a new shopping cart object is created.
- Add the new shopping cart object to the shopping cart list.
- If there is a shopping cart in the shopping cart list;
- Query whether the item exists in the shopping cart list.
- If not, add new shopping cart details;
- If so, add quantity to the original shopping cart details and change the amount.
Click on the submission order on the order settlement page to save the shopping cart in the order form and order detail table, and clear the shopping cart data.
Sweep Payment
We call the remote payment interface through the HttpClient tool class.
Interface Links: https://api.mch.weixin.qq.com/pay/orderquery
Specific parameters refer to the query order API. Query orders are invoked by polling in the controller method (3 seconds interval). When the return status is success, the result is returned in the controller method. The front-end code jumps to the success page after it receives the result.
If the user has not paid for the two-dimensional code page or turned off the payment page, the code will always call the Wechat interface circularly, which will cause great pressure on the program. So add a time limit or cycle number limit and jump out of the cycle when the time or cycle number exceeds.
@RequestMapping("/queryPayStatus") public Result queryPayStatus(String out_trade_no){ Result result=null; int x=0; while(true){ //Call query interface ....... try { Thread.sleep(3000);//Three seconds apart } catch (InterruptedException e) { e.printStackTrace(); } //In order not to let the loop run endlessly, we define a loop variable, which exits the loop if it exceeds this value for 5 minutes. x++; if(x>=100){ result=new Result(false, "Two-dimensional code timeout"); break; } } return result; }
Other technical points
- MyBatis Paging Plug-in Page Helper
- Front-end layered development
- Dropdown box select2
- BCrypt encryption algorithm
- kindeditor Rich Text Editor
- Distributed File Server FastDFS
- Redis Cached Database - Spring Data Redis
- Search Solr-Spring Data Solr
- Chinese parser IK Analyzer
- Solr (highlighting, sorting list, filtering query, price range search, sorting)
- Web Static Freemarker
- FTL Directive
- Message middleware ActiveMQ reduces coupling
- SpringBoot Microservice Framework
- Short Message Delivery Platform - Aliyu
- Single sign-on CAS
- CAS Client and Spring Security Integration
- Cookie and Redis Storage Shopping Cart
- JS cross-domain request
- Distributed ID Generator (snowflake algorithm)
- Two-Dimensional Code Generation
- Wechat Payment SDK
- Redis Implements Second Kill Service
- Task Scheduling Spring Task
- Maven Profile
- MongoDB database
- Zookeeper Cluster
- SolrCloud Cluster
- Redis Cluster Cluster Cluster
- Database Fragmentation Middleware-MyCat
- Reverse proxy server Nginx
- Docker container