电商系统店铺个性化域名实现

一、背景介绍

在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博客。

你可能感兴趣的:(架构,Java)