一、背景
之前的文章介绍了用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>