電商系統店鋪個性化域名實現

一、背景介紹

在C2C電商系統中,用戶可以申請成爲賣家,然後開設自己的店鋪。爲了更利於傳播,讓會員更容易記住,一般會設置店鋪的個性域名。如:良品鋪子在某貓的個性域名是:lppz.xxmall.com。

二、設計原理

在設計這套系統時,主要是通過設置域名的泛解析到二級或者三級域名,然後根據域名前綴,在程序中轉換成對應的店鋪id。從而完成個性化域名跳轉到對應的店鋪網站首頁。

三、程序實現

1. 設置域名泛解析

假設域名是:abc.com,設置所有匹配*.m.abc.com的三級域名解析到服務器上,如下圖:
這裏寫圖片描述

2. 配置Nginx轉發

這裏將所有的域名,rewrite成指定的url前綴:/site/domain。domain代表*所匹配的三級域名,代碼如下:

server {
       listen      80;
       server_name *.m.abc.cn;
       #設置靜態文件路徑,不轉發
       location ~ ^/static/ {
             root /webser/test/webapps/test-mobile;
        }

        #設置域名轉發到固定URL:/site/domain
       location / {
            set $subdomain default;
            if ( $http_host ~* "^(.*)\.m\.abc\.cn"){
                set $subdomain $1;
            }
            rewrite ^/(.*)$ /site/$subdomain/$1 break;
            proxy_pass http://localhost:8088;
            proxy_set_header   Host    $host;
            proxy_set_header   X-Real-IP   $remote_addr;
            proxy_set_header   X-Forwarded-For 
            $proxy_add_x_forwarded_for;
       }
    }
3. 配置Controller

這裏使用Spring-mvc做爲mvc框架。首先定義一個Controller基類BaseController,所有的controller都繼承它。

public class BaseController {

}

再定義店鋪的Controller類SiteController,攔截所有URL包含/site/domain的請求。這樣配置的泛解析域名都會進入這個Controller

@Controller
@RequestMapping("/site/{domain}")
public class SiteController extends BaseController{

}
3.1 實現域名轉換成店鋪id

方法一:在進入SiteController的某個方法後,通過@PathVariable註解,得到domain,然後在數據庫中根據domain查詢出對於的店鋪id。

@Controller
@RequestMapping("/site/{domain}")
    @Autowired
    private SiteService siteService;

    @RequestMapping("/index")
    public String index(@PathVariable String domain){
        //得到店鋪id
        Site site = siteService.findSiteByDomain(domain);
    }
}

這樣的寫法有個問題,就是每個方法都要寫這樣的一段代碼。假如我們可以在進入Controller某個方法前,就能通過domain得到店鋪id,那就更好了。那麼Spring-mvc中有沒有在進入某個Controller的方法前執行的註解呢?

方法二:在Spring-mvc的註解中,有個註解會在進入Controller每個方法前執行。這個註解就是@ModelAttribute。被@ModelAttribute註釋的方法會在此controller每個方法執行前被執行,因此對於一個controller映射多個URL的用法來說,要謹慎使用。
有了這個註解,我們可以在BaseController基類中,定義一個方法來實現域名轉換成店鋪id的操作。代碼如下:

public class BaseController {
    //定義店鋪id
    protected Long siteId = 0L;

    @Autowired
    private SiteService siteService;

    /**
     * @Title: getSiteId 
     * @Description: 將domain轉換成店鋪id
     * @throws
     */
    @ModelAttribute
    public void getSiteId(@PathVariable String domain,Model model,HttpServletRequest request,HttpServletResponse response){
        Site site = siteService.findSiteByDomain(domain);
        if(site != null){
            siteId = site.getId();
        }else{
            throw new RuntimeException("域名不存在");
        }


    }
}

在上面的代碼中,我們定義了一個成員變量siteId,即店鋪id,這樣在所有繼承BaseController的基類中,可以直接使用siteId來獲取店鋪的數據。
通過@ModelAttribute註解,在所有進入Controller方法前,將域名domain轉換成店鋪id即siteId。
這裏店鋪我是定義爲Site對象,然後直接從數據庫裏查詢得到。其實可以有優化的方案。通常店鋪的個性域名不會隨意更改,對於改動比較少的數據,我們可以在程序中緩存起來。所以可以將所有店鋪對象和domain對應關係,通過key-value的形式,存在內存map或者redis中,這樣獲取店鋪時,直接通過domain做爲key,就可以得到site對象了。

通過這幾步,即完成了類似淘寶店鋪設置個性化域名的功能。
PS:這裏只是提供了一種設計思路和簡單的實現,在併發量上千萬甚至更大的情況下,這塊會更加複雜。如需瞭解更多,請加我個人微信:jerry0914,請備註csdn博客。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章