Spring最近换域名了,去转转,发现了一个有意思的项目:spring mobile。

http://projects.spring.io/spring-mobile/

这个项目有很多实用的功能,如识别访问我们网站的设备是什么类型的(手机,平板,PC),据域名或者url来切换不同访问内容,据不同的访问设备转到不同的view中。

识别访问设备类型的核心代码在org.springframework.mobile.device.LiteDeviceResolver 类中,这个类实际上根据http请求头部的User-Agent的内容来判断设备到底是哪种类型的。

可以看到,这个类实际上是很简单的。不过字符串的匹配算法可能可以优化下。

[java] view
plain
copy

  1. public class LiteDeviceResolver implements DeviceResolver {
  2. private final List<String> mobileUserAgentPrefixes = new ArrayList<String>();
  3. private final List<String> mobileUserAgentKeywords = new ArrayList<String>();
  4. private final List<String> tabletUserAgentKeywords = new ArrayList<String>();
  5. private final List<String> normalUserAgentKeywords = new ArrayList<String>();
  6. public LiteDeviceResolver() {
  7. init();
  8. }
  9. public LiteDeviceResolver(List<String> normalUserAgentKeywords) {
  10. init();
  11. this.normalUserAgentKeywords.addAll(normalUserAgentKeywords);
  12. }
  13. public Device resolveDevice(HttpServletRequest request) {
  14. String userAgent = request.getHeader("User-Agent");
  15. // UserAgent keyword detection of Normal devices
  16. if (userAgent != null) {
  17. userAgent = userAgent.toLowerCase();
  18. for (String keyword : normalUserAgentKeywords) {
  19. if (userAgent.contains(keyword)) {
  20. return resolveFallback(request);
  21. }
  22. }
  23. }
  24. // UAProf detection
  25. if (request.getHeader("x-wap-profile") != null || request.getHeader("Profile") != null) {
  26. return LiteDevice.MOBILE_INSTANCE;
  27. }
  28. // User-Agent prefix detection
  29. if (userAgent != null && userAgent.length() >= 4) {
  30. String prefix = userAgent.substring(0, 4).toLowerCase();
  31. if (mobileUserAgentPrefixes.contains(prefix)) {
  32. return LiteDevice.MOBILE_INSTANCE;
  33. }
  34. }
  35. // Accept-header based detection
  36. String accept = request.getHeader("Accept");
  37. if (accept != null && accept.contains("wap")) {
  38. return LiteDevice.MOBILE_INSTANCE;
  39. }
  40. // UserAgent keyword detection for Mobile and Tablet devices
  41. if (userAgent != null) {
  42. userAgent = userAgent.toLowerCase();
  43. // Android special case
  44. if (userAgent.contains("android") && !userAgent.contains("mobile")) {
  45. return LiteDevice.TABLET_INSTANCE;
  46. }
  47. // Kindle Fire special case
  48. if (userAgent.contains("silk") && !userAgent.contains("mobile")) {
  49. return LiteDevice.TABLET_INSTANCE;
  50. }
  51. for (String keyword : tabletUserAgentKeywords) {
  52. if (userAgent.contains(keyword)) {
  53. return LiteDevice.TABLET_INSTANCE;
  54. }
  55. }
  56. for (String keyword : mobileUserAgentKeywords) {
  57. if (userAgent.contains(keyword)) {
  58. return LiteDevice.MOBILE_INSTANCE;
  59. }
  60. }
  61. }
  62. // OperaMini special case
  63. @SuppressWarnings("rawtypes")
  64. Enumeration headers = request.getHeaderNames();
  65. while (headers.hasMoreElements()) {
  66. String header = (String) headers.nextElement();
  67. if (header.contains("OperaMini")) {
  68. return LiteDevice.MOBILE_INSTANCE;
  69. }
  70. }
  71. return resolveFallback(request);
  72. }
  73. // subclassing hooks
  74. /**
  75. * List of user agent prefixes that identify mobile devices.
  76. * Used primarily to match by operator or handset manufacturer.
  77. */
  78. protected List<String> getMobileUserAgentPrefixes() {
  79. return mobileUserAgentPrefixes;
  80. }
  81. /**
  82. * List of user agent keywords that identify mobile devices.
  83. * Used primarily to match by mobile platform or operating system.
  84. */
  85. protected List<String> getMobileUserAgentKeywords() {
  86. return mobileUserAgentKeywords;
  87. }
  88. /**
  89. * List of user agent keywords that identify tablet devices.
  90. * Used primarily to match by tablet platform or operating system.
  91. */
  92. protected List<String> getTabletUserAgentKeywords() {
  93. return tabletUserAgentKeywords;
  94. }
  95. /**
  96. * List of user agent keywords that identify normal devices.
  97. * Any items in this list take precedence over the mobile and
  98. * tablet user agent keywords, effectively overriding those.
  99. */
  100. protected List<String> getNormalUserAgentKeywords() {
  101. return normalUserAgentKeywords;
  102. }
  103. /**
  104. * Initialize this device resolver implementation.
  105. * Registers the known set of device signature strings.
  106. * Subclasses may override to register additional strings.
  107. */
  108. protected void init() {
  109. getMobileUserAgentPrefixes().addAll(Arrays.asList(KNOWN_MOBILE_USER_AGENT_PREFIXES));
  110. getMobileUserAgentKeywords().addAll(Arrays.asList(KNOWN_MOBILE_USER_AGENT_KEYWORDS));
  111. getTabletUserAgentKeywords().addAll(Arrays.asList(KNOWN_TABLET_USER_AGENT_KEYWORDS));
  112. }
  113. /**
  114. * Fallback called if no mobile device is matched by this resolver.
  115. * The default implementation of this method returns a "normal" {@link Device} that is neither mobile or a tablet.
  116. * Subclasses may override to try additional mobile or tablet device matching before falling back to a "normal" device.
  117. */
  118. protected Device resolveFallback(HttpServletRequest request) {
  119. return LiteDevice.NORMAL_INSTANCE;
  120. }
  121. // internal helpers
  122. private static final String[] KNOWN_MOBILE_USER_AGENT_PREFIXES = new String[] { "w3c ", "w3c-", "acs-", "alav",
  123. "alca", "amoi", "audi", "avan", "benq", "bird", "blac", "blaz", "brew", "cell", "cldc", "cmd-", "dang",
  124. "doco", "eric", "hipt", "htc_", "inno", "ipaq", "ipod", "jigs", "kddi", "keji", "leno", "lg-c", "lg-d",
  125. "lg-g", "lge-", "lg/u", "maui", "maxo", "midp", "mits", "mmef", "mobi", "mot-", "moto", "mwbp", "nec-",
  126. "newt", "noki", "palm", "pana", "pant", "phil", "play", "port", "prox", "qwap", "sage", "sams", "sany",
  127. "sch-", "sec-", "send", "seri", "sgh-", "shar", "sie-", "siem", "smal", "smar", "sony", "sph-", "symb",
  128. "t-mo", "teli", "tim-", "tosh", "tsm-", "upg1", "upsi", "vk-v", "voda", "wap-", "wapa", "wapi", "wapp",
  129. "wapr", "webc", "winw", "winw", "xda ", "xda-" };
  130. private static final String[] KNOWN_MOBILE_USER_AGENT_KEYWORDS = new String[] { "blackberry", "webos", "ipod",
  131. "lge vx", "midp", "maemo", "mmp", "mobile", "netfront", "hiptop", "nintendo DS", "novarra", "openweb",
  132. "opera mobi", "opera mini", "palm", "psp", "phone", "smartphone", "symbian", "up.browser", "up.link",
  133. "wap", "windows ce" };
  134. private static final String[] KNOWN_TABLET_USER_AGENT_KEYWORDS = new String[] { "ipad", "playbook", "hp-tablet",
  135. "kindle" };
  136. }

Spring Mobile是如何判断访问设备的类型的的更多相关文章

  1. Java判断访问设备为手机、微信、PC工具类

    package com.lwj.util; import javax.servlet.http.HttpServletRequest; /** * 判断访问设备为PC或者手机--工具类 * * @de ...

  2. JS判断访问设备、客户端操作系统类型

    先给出一个实例:判断windows.linux.android 复制以下代码另存为html文件即可. <html> <head> <title>判断操作系统< ...

  3. [转]JS判断访问设备、客户端操作系统类型

    本文转自:http://www.cnblogs.com/duanguyuan/p/3534470.html 先给出一个实例:判断windows.linux.android 复制以下代码另存为html文 ...

  4. JS判断访问设备(userAgent)加载不同页面 JS判断客户端操作系统类型(platform)

    //平台.设备和操作系统 var system ={ win : false, mac : false, xll : false }; //检测平台 var p = navigator.platfor ...

  5. PHP和js判断访问设备是否是微信浏览器实例

    PHP和js判断访问设备是否是微信浏览器实例,代码非常精简,适合新手学习. js判断是否是微信浏览器: 1 function is_weixin() { 2 var ua = window.navig ...

  6. 判断访问浏览器客户端类型(pc,mac,ipad,iphone,android)

    <script type="text/javascript"> //平台.设备和操作系统 var system = { win: false, mac: false, ...

  7. JS判断访问设备是移动设备还是pc

    <scripttype="text/javascript"> function browserRedirect() { var sUserAgent= navigato ...

  8. 如何判断 ios设备的类型(iphone,ipod,ipad)

    功能函数: -(bool)checkDevice:(NSString*)name { NSString* deviceType = [UIDevice currentDevice].model; NS ...

  9. Spring Mobile——探测客户端设备和系统

    Spring Mobile--探测客户端设备和系统 今天闲来无事,浏览Spring的官方网站,发现了Spring Mobile项目,之前也看到过,还以为是针对手机端的项目,并没有细看.今天仔细看了一下 ...

随机推荐

  1. Codeforces Round #198 (Div. 2) B. Maximal Area Quadrilateral

    B. Maximal Area Quadrilateral time limit per test 1 second memory limit per test 256 megabytes input ...

  2. Android Texting(2)Testing Fundamentals 测试基础篇

    Testing Fundamentals The Android testing framework, an integral part of the development environment, ...

  3. 模拟Hibernate框架的小demo

    该程序为尚学堂马士兵老师讲解,模拟了hibernate的原理,主要应用了字符串拼接,反射知识. step1,新建数据库 use jd; create table _student( _id int(1 ...

  4. PyQt中如何隐藏Menu

    PyQt中隐藏一个Menu Item,可以通过QAction的setVisible(False)来设置,而QMenu的setVisible(False)是不管用的. 现在问题来了,我们有一个菜单,它有 ...

  5. 使用zxing生成二维码 - servlet形式

    因为项目有个功能需要打印二维码,因为我比较喜欢使用html+css+js实现,所以首先想到的是jquery.qrcode.js插件,这个插件可以用canvas和table生成二维码,效果也不错,不过对 ...

  6. WebLech是一个功能强大的Web站点下载与镜像工具

    WebLech是一个功能强大的Web站点下载与镜像工具.它支持按功能需求来下载web站点并能够尽可能模仿标准Web浏览器的行为.WebLech有一个功能控制台并采用多线程操作. http://sour ...

  7. xen虚拟机安装实践

    xen虚拟机环境安装,用了2天的时间摸索,终于出来了,给大家分享一下. 1.安装宿主环境,我使用的是Centos6.3 2.安装xend,参考了一篇老外的文章,基本比较顺利. 地址:http://xe ...

  8. [置顶] 自定义java Annotation快速入门与提高

    我们先来看看一个简单的注解类定义 import java.lang.annotation.Documented; import java.lang.annotation.Retention; impo ...

  9. JavaScript 字符串编码函数

    JavaScript中有三个可以对字符串编码的函数,分别是: escape,encodeURI,encodeURIComponent,相应3个解码函数:unescape,decodeURI,decod ...

  10. 07-IOSCore - CoreData补充、音频视频

    xml被plist取代了  数据库被coredata取代了 一.Core Data 高级补充 1. Core Data 本质是什么?操作数据库的数据 ORM Object Relationship M ...