[Java Spring open source project] operation, analysis and summary of neebee mall project

Posted by suepahfly on Wed, 19 Jan 2022 12:25:01 +0100

Project introduction

**Project address:** https://github.com/newbee-ltd/newbee-mall

**Project Description: * * NewBee mall project is a set of e-commerce system, including NewBee mall system and NewBee mall admin mall background management system, based on spring boot 2 X and related technology stack development. The front desk mall system includes home page portal, commodity classification, new product launch, home page rotation, commodity recommendation, commodity search, commodity display, shopping cart, order settlement, order process, personal order management, member center, help center and other modules. The background management system includes data panel, rotation chart management, commodity management, order management, member management, classification management, setting and other modules.

Verified by the author, it is a Spring project worth seeing!

Project operation

To run this project, you need to configure it accordingly:

  • Install Mysql

For Mac computers, refer to: Installing mysql on Mac.

After Mysql is installed, create a new database and run NewBee mall schema SQL file to insert data into the database. Refer to: How to insert sql file into database.

  • Configure Mysql

Modify application The mysql database name in the properties file is its own database name:

spring.datasource.name=newbee(Own database name)
spring.datasource.username=root
spring.datasource.password=12345678
  • Unzip img and modify the path

Upload the file under the project path Zip unzip and record the path;

Modify the path in common / constants:

//public final static String FILE_UPLOAD_DIC = "/opt/image/upload/";// The default url prefix of the uploaded file can be modified according to the deployment settings
    public final static String FILE_UPLOAD_DIC = "/Users/xiuyi/Desktop/javaer/newbee-mall/src/main/resources/upload/";
  • Run, access

After running successfully, open the web page and visit: localhost:28089.

For problems in the project, please refer to: How to run new bee.

Project framework

The overall framework of the project is as follows:

Among them,

  • Common: define some common field names;
  • util: provides some static help methods. Such as email format verification, MD5 code generation, etc;
  • config: configuration of WebMvcConfigure, mainly setting interceptors and resource files;
  • dao: interactive interface with the data layer to obtain goods information, user information, order information, etc; The database used in the project is Mybatis, and the mapping relationship between dao interface and database is configured through XML;
  • Interceptor: the specific implementation of interceptor, which completes authentication and real-time update of the number of shopping carts;
  • Controller: the controller in the MVC framework, which calls the corresponding service layer for logical processing according to the request of the web end;
  • entity: common field class in the project;
  • Service: service layer, called by the controller;

Functional subdivision

This part further analyzes the various functions of the project, straightens out the call relationship and adds some details.

In fact, this is a typical MVC project, namely model view Controller. According to the corresponding client request, Spring MVC schedules the corresponding Controller for processing. The Controller calls service for business logic processing, and then gives it to Thymeleaf template engine to render the result Entity and return the processing result to the user for display on the browser. The whole process is as follows:

Mall home page

Home page, i.e. visit: Web address / index (or /, or /) to obtain the home page of Xinfeng mall.

In the IndexController, when receiving the request from the client "/", access the database to obtain classification data, rotation map, new products and recommendation data, generate html via the template engine (thymeleaf) and return it to the client:

@GetMapping({"/index", "/", "/index.html"})
public String indexPage(HttpServletRequest request) {
    List<NewBeeMallIndexCategoryVO> categories = newBeeMallCategoryService.getCategoriesForIndex();
    if (CollectionUtils.isEmpty(categories)) {
        return "error/error_5xx";
    }
    List<NewBeeMallIndexCarouselVO> carousels = newBeeMallCarouselService.getCarouselsForIndex(Constants.INDEX_CAROUSEL_NUMBER);
    List<NewBeeMallIndexConfigGoodsVO> hotGoodses = newBeeMallIndexConfigService.getConfigGoodsesForIndex(IndexConfigTypeEnum.INDEX_GOODS_HOT.getType(), Constants.INDEX_GOODS_HOT_NUMBER);
    List<NewBeeMallIndexConfigGoodsVO> newGoodses = newBeeMallIndexConfigService.getConfigGoodsesForIndex(IndexConfigTypeEnum.INDEX_GOODS_NEW.getType(), Constants.INDEX_GOODS_NEW_NUMBER);
    List<NewBeeMallIndexConfigGoodsVO> recommendGoodses = newBeeMallIndexConfigService.getConfigGoodsesForIndex(IndexConfigTypeEnum.INDEX_GOODS_RECOMMOND.getType(), Constants.INDEX_GOODS_RECOMMOND_NUMBER);
    request.setAttribute("categories", categories);//Classified data
    request.setAttribute("carousels", carousels);//Rotation chart
    request.setAttribute("hotGoodses", hotGoodses);//Hot selling goods
    request.setAttribute("newGoodses", newGoodses);//New products
    request.setAttribute("recommendGoodses", recommendGoodses);//Pick of the week
    return "mall/index";
}

Note that the return value of the above Controller is "mail/index" - this is because the default configuration of thymeleaf integrated with Spring Boot will automatically render * * classpath:templates / Web page name** Thymeleaf's detailed tutorial is available for reference Thymeleaf grammarThymeleaf details.

Therefore, when using the Thymeleaf template engine, the Controller only needs to return the specified web page name instead of rendering through ModelView like WebMVC:

@RequestMapping(value = "/greeting") 
public ModelAndView test(ModelAndView mv) { 
		mv.setViewName("/greeting"); 
		mv.addObject("title","Welcome Thymeleaf!"); 
		return mv; 
} 

User registration and login

Click the register button to jump to the user login interface:

The corresponding paths of the two buttons are / rigister and / login. The requested path is mall/PersonalController. If the login and registration pages are obtained, the corresponding template engine will be called for rendering:

		@GetMapping({"/login", "login.html"})
    public String loginPage() {
        return "mall/login";
    }

    @GetMapping({"/register", "register.html"})
    public String registerPage() {
        return "mall/register";
    }

If it is to obtain the login and registration form, you should call the corresponding post method. Take login as an example:

@PostMapping("/login")
@ResponseBody
public Result login(@RequestParam("loginName") String loginName,
                    @RequestParam("verifyCode") String verifyCode,
                    @RequestParam("password") String password,
                    HttpSession httpSession) {
    if (StringUtils.isEmpty(loginName)) {
        return ResultGenerator.genFailResult(ServiceResultEnum.LOGIN_NAME_NULL.getResult());
    }
    if (StringUtils.isEmpty(password)) {
        return ResultGenerator.genFailResult(ServiceResultEnum.LOGIN_PASSWORD_NULL.getResult());
    }
    if (StringUtils.isEmpty(verifyCode)) {
        return ResultGenerator.genFailResult(ServiceResultEnum.LOGIN_VERIFY_CODE_NULL.getResult());
    }
    String kaptchaCode = httpSession.getAttribute(Constants.MALL_VERIFY_CODE_KEY) + "";
    if (StringUtils.isEmpty(kaptchaCode) || !verifyCode.toLowerCase().equals(kaptchaCode)) {
        return ResultGenerator.genFailResult(ServiceResultEnum.LOGIN_VERIFY_CODE_ERROR.getResult());
    }
    String loginResult = newBeeMallUserService.login(loginName, MD5Util.MD5Encode(password, "UTF-8"), httpSession);
    //Login succeeded
    if (ServiceResultEnum.SUCCESS.getResult().equals(loginResult)) {
        //Delete verifyCode in session
        httpSession.removeAttribute(Constants.MALL_VERIFY_CODE_KEY);
        return ResultGenerator.genSuccessResult();
    }
    //Login failed
    return ResultGenerator.genFailResult(loginResult);
}

It is worth noting that when processing login, the basic format verification of user name and password will be carried out first, and then handed over to the database for verification.

Product details page

Take HUAWEI mate30 Pro as an example:

Its controller is mail/GoodsController, which obtains commodity data by accessing the database and puts it into the template engine for rendering:

@GetMapping("/goods/detail/{goodsId}")
public String detailPage(@PathVariable("goodsId") Long goodsId, HttpServletRequest request) {
    if (goodsId < 1) {
        return "error/error_5xx";
    }
    NewBeeMallGoods goods = newBeeMallGoodsService.getNewBeeMallGoodsById(goodsId);
    if (goods == null) {
        NewBeeMallException.fail(ServiceResultEnum.GOODS_NOT_EXIST.getResult());
    }
    if (Constants.SELL_STATUS_UP != goods.getGoodsSellStatus()) {
        NewBeeMallException.fail(ServiceResultEnum.GOODS_PUT_DOWN.getResult());
    }
    NewBeeMallGoodsDetailVO goodsDetailVO = new NewBeeMallGoodsDetailVO();
    BeanUtil.copyProperties(goods, goodsDetailVO);
    goodsDetailVO.setGoodsCarouselList(goods.getGoodsCarousel().split(","));
    request.setAttribute("goodsDetail", goodsDetailVO);
    return "mall/detail";
}

Product search

When searching for goods, its controller is also mail/GoodsController, which searches for goods corresponding to attributes in the database through keywords

And display. There is also a pagination design to limit the number of goods displayed on each page, as well as sorting properties:

In addition, it can be seen that the interface used by the search column here is the same as that used by the classification column on the home page, except that keyword is used for search, and category is used for classification.

@GetMapping({"/search", "/search.html"})
public String searchPage(@RequestParam Map<String, Object> params, HttpServletRequest request) {
    if (StringUtils.isEmpty(params.get("page"))) {
        params.put("page", 1);
    }
    params.put("limit", Constants.GOODS_SEARCH_PAGE_LIMIT);
    //Encapsulate classified data
    if (params.containsKey("goodsCategoryId") && !StringUtils.isEmpty(params.get("goodsCategoryId") + "")) {
        Long categoryId = Long.valueOf(params.get("goodsCategoryId") + "");
        SearchPageCategoryVO searchPageCategoryVO = newBeeMallCategoryService.getCategoriesForSearch(categoryId);
        if (searchPageCategoryVO != null) {
            request.setAttribute("goodsCategoryId", categoryId);
            request.setAttribute("searchPageCategoryVO", searchPageCategoryVO);
        }
    }
    //Package parameters for front-end echo
    if (params.containsKey("orderBy") && !StringUtils.isEmpty(params.get("orderBy") + "")) {
        request.setAttribute("orderBy", params.get("orderBy") + "");
    }
    String keyword = "";
    //Filter the keyword to remove spaces
    if (params.containsKey("keyword") && !StringUtils.isEmpty((params.get("keyword") + "").trim())) {
        keyword = params.get("keyword") + "";
    }
    request.setAttribute("keyword", keyword);
    params.put("keyword", keyword);
    //Search for goods on the shelf
    params.put("goodsSellStatus", Constants.SELL_STATUS_UP);
    //Encapsulate commodity data
    PageQueryUtil pageUtil = new PageQueryUtil(params);
    request.setAttribute("pageResult", newBeeMallGoodsService.searchNewBeeMallGoods(pageUtil));
    return "mall/search";
}

In fact, the commodity search part of these links is what I am most interested in: how does it realize the search?

The author tested the search system and the results are more accurate. Is it difficult to integrate the search engine? Driven by curiosity, he continued to dig below until:

<select id="findNewBeeMallGoodsListBySearch" parameterType="Map" resultMap="BaseResultMap">
    select
    <include refid="Base_Column_List"/>
    from tb_newbee_mall_goods_info
    <where>
        <if test="keyword!=null and keyword!=''">
            and (goods_name like CONCAT('%',#{keyword},'%') or goods_intro like CONCAT('%',#{keyword},'%'))
        </if>
        <if test="goodsCategoryId!=null and goodsCategoryId!=''">
            and goods_category_id = #{goodsCategoryId}
        </if>
        <if test="goodsSellStatus!=null">
            and goods_sell_status = #{goodsSellStatus}
        </if>
    </where>
    <if test="orderBy!=null and orderBy!=''">
        <choose>
            <when test="orderBy == 'new'">
                <!-- In reverse order of release time -->
                order by goods_id desc
            </when>
            <when test="orderBy == 'price'">
                <!-- Rank from small to large according to the selling price -->
                order by selling_price asc
            </when>
            <otherwise>
                <!-- By default, the inventory quantity is sorted from large to small -->
                order by stock_num desc
            </otherwise>
        </choose>
    </if>
    <if test="start!=null and limit!=null">
        limit #{start},#{limit}
    </if>
</select>

From the above dynamic Sql statement of Mybatis, it can be seen that the whole commodity search system is actually provided by the underlying Mysql database, and the so-called commodity search is only matched with the commodity name and commodity introduction by the way of Like plus% wildcard.

This search method is sad when it encounters fuzzy nouns or wrong nouns. It can't find anything, and it searches in the way of wildcards. When there is a large amount of data, the efficiency is extremely low. In the real e-commerce scenario, commodity search is an extremely important component. Generally, the search engine based on inverted index database (ES, OpenSearch, etc.) provides commodity search services.

Order system

All logic controls related to shopping carts are in the mall/shoppingcartController, which will not be repeated for the time being:

By the way, the address will be verified when paying. It's great!

PS: in a robust system, data validation in the right place can effectively prevent errors.

Background management system

The background management system allows businesses to manage their own goods (user name: admin, password: 123456), such as adding goods, setting rotation chart, modifying sorting, etc

The background management system can carry out commodity management, order management, member management, etc. if the previous system is to query the database, then this link is mainly to modify the database. (as long as current developers can CRUD, they are not afraid of no food)

This background management system is amazing!

It can be said that the front-end, database, dynamic web page and other technologies are all used, so it is necessary to study carefully!

summary

The content of this open source project contains too much knowledge to learn:

  • Spring Boot configuration
  • Use of Spring MVC
  • Thymeleaf template engine
  • Use of Mybatis
  • Mysql configuration
  • Interceptot interceptor
  • Authentication
  • kaptcha verification code generation
  • AdminLTE dashboard * * * * and other knowledge

It can be said that to fully understand this project requires a lot of preparation knowledge, but there are also many gains!

This open source project is really good. Thank you for sharing!

Topics: Java Database MySQL Spring Spring Boot