一、背景
之前的文章介绍了用Java 做301重定向,即使用Url Rewrite 进行URL 重写来实现网站的伪静态。现在产品这边又多了一个需求,需要网站支持二级域名跳转,比如访问abc.baidu.com 能够跳转到 www.baidu.com/abc。这个功能其实和301 重定向原理是一样的,只不过我们需要自己自定义一个重定向规则。
二、代码实现
UrlWriterFactory 工厂类
public class UrlWriterFactory {
private static Log logger = LogFactory.getLog(UrlWriterFactory.class);
private static final String FORWARD = "forward";
private static final String REDIRECT = "redirect";
private static final String DEFAULT_CONFIG_FILE_NAME = "config/urlrewrite.xml";
private static String urlWriterConfigName;
/**
* 版本号
*/
private Long version = System.currentTimeMillis();
private static List<UrlWriter> urlPatternList = new ArrayList<UrlWriter>();
public void init() {
if (StringUtils.isBlank(urlWriterConfigName)) {
urlWriterConfigName = DEFAULT_CONFIG_FILE_NAME;
}
InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(urlWriterConfigName);
if (null == inputStream) {
throw new RuntimeException("没有配置urlrewrite.xml");
}
urlPatternList = initUrlWriter(inputStream);
}
@SuppressWarnings("unchecked")
private List<UrlWriter> initUrlWriter(InputStream inputStream) {
List<UrlWriter> urlPatternList = new ArrayList<UrlWriter>();
SAXReader reader = new SAXReader();
try {
Document doc = reader.read(inputStream);
List<Node> nodes = doc.selectNodes("urlrewrite/rule");
for (Node elm : nodes) {
UrlWriter urlMapping = new UrlWriter();
String from = ((Element) elm).elementText("from");
from = StringUtils.isBlank(from) ? "" : from;
urlMapping.setFrom(from);
String to = ((Element) elm).elementText("to");
to = StringUtils.isBlank(to) ? "" : to;
urlMapping.setTo(to);
Attribute attribute = ((Element) elm).element("to").attribute("type");
String type = FORWARD;
if (null != attribute) {
if (StringUtils.isBlank(attribute.getValue())) {
type = attribute.getValue();
}
}
urlMapping.setType(type);
urlPatternList.add(urlMapping);
}
return urlPatternList;
} catch (DocumentException e) {
logger.error("解析url.xml时发现异常:" + e);
}
return urlPatternList;
}
public static UrlResult getUrlResult(String url) {
if (StringUtils.isEmpty(url)) {
return null;
}
url = filterUrlStyle(url);
UrlResult urlResult = new UrlResult(false, "");
for (UrlWriter urlMapping : urlPatternList) {
Pattern pattern = Pattern.compile(urlMapping.getFrom());
Matcher matcher = pattern.matcher(url);
if (matcher.find()) {
// urlResult.setUrl(matcher.replaceAll(urlMapping.getTo()));
String urlTo = urlMapping.getTo();
for (int i = 1; i <= matcher.groupCount(); i++) {
urlTo = urlTo.replace("$" + i, matcher.group(i));
}
if (!urlTo.contains(".html")) {
urlTo = urlTo + File.separator + "index.html";
}
urlResult.setUrl(urlTo);
if (urlMapping.getType().equals(REDIRECT)) {
urlResult.setFlag(true);
}
return urlResult;
}
}
return urlResult;
}
public static class UrlResult {
private boolean flag = false;
private String url = "";
public UrlResult(boolean flag, String url) {
super();
this.flag = flag;
this.url = url;
}
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
}
public String getUrlWriterConfigName() {
return urlWriterConfigName;
}
public void setUrlWriterConfigName(String urlWriterConfigName) {
UrlWriterFactory.urlWriterConfigName = urlWriterConfigName;
}
public Long getVersion() {
return version;
}
public void setVersion(Long version) {
this.version = version;
}
private static String filterUrlStyle(String url) {
if (url.indexOf("://") != -1) {
url = url.substring(url.indexOf("://") + 3);
}
// if (url.length() > 1 && url.endsWith("/")) {
// url = url.substring(0, url.length() - 1);
// }
return url;
}
public static boolean checkIfSecondDomain(String url) {
if (StringUtil.isBlank(url)) {
return false;
}
if (!url.contains("\\.company")) {
return false;
}
return false;
}
UrlWriter 实体bean
public class UrlWriter {
private String from;
private String to;
private String type;
public String getFrom() {
return from;
}
public void setFrom(String from) {
this.from = from;
}
public String getTo() {
return to;
}
public void setTo(String to) {
this.to = to;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}
UrlWriterFilter 过滤器方法
public class UrlWriterFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
String requestURL = httpServletRequest.getRequestURL().toString();
System.out.println("URL的值" + requestURL);
// 屏蔽镜像网站
if (requestURL.indexOf(".xiniu1688.com") == -1) {
request.getRequestDispatcher("/error/404.do").forward(request, response);// 跳转到信息提示页面!!
return;
}
// 非二级域名直接过滤掉
if (requestURL.startsWith("http://www.xxxx.com") || requestURL.startsWith("http://xxxx.com")) {
chain.doFilter(request, response);
return;
}
UrlWriterFactory uf = new UrlWriterFactory();
uf.init();
UrlResult urlResult = UrlWriterFactory.getUrlResult(requestURL);
if (null != urlResult && !StringUtil.isBlank(urlResult.getUrl())) {
String realPath = urlResult.getUrl();
if (urlResult.isFlag()) {
httpServletResponse.sendRedirect(realPath);
return;
} else {
if (!realPath.startsWith("/")) {
realPath = "/" + realPath;
}
httpServletRequest.getRequestDispatcher(realPath).forward(request, response);
return;
}
} else {
chain.doFilter(request, response);
}
}
@Override
public void destroy() {
}
/*
* (non-Javadoc)
*
* @see javax.servlet.Filter#init(javax.servlet.FilterConfig)
*/
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
}
urlrewrite.xml 配置文件,放在根目录下面的conf 文件夹下
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE urlrewrite PUBLIC "-//tuckey.org//DTD UrlRewrite 4.0//EN"
"http://www.tuckey.org/res/dtds/urlrewrite4.0.dtd">
<urlrewrite>
<rule>
<from>^(.*).xxxx.com/(.*)$</from>
<to>/company/$1/$2</to>
</rule>
</urlrewrite>
web.xml 配置
<!-- urlrewriter 重写 -->
<filter>
<filter-name>SecDomainUrlWriterFilter</filter-name>
<filter-class>com.xxx.xxx.urlwriter.UrlWriterFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>SecDomainUrlWriterFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>