728x90
반응형
스프링에서 브라우저 정보(UserAgent)처리예제


웹개발을 하다보면 브라우져와 OS정보가 들어있는 UserAgent를 이용해서

여러 처리를 할 필요가 가끔 생깁니다.

이걸 실무서 어떻게 하면 깔끔하게 구현할까 고민하다가 다음과 같이 해보았습니다.



일단 저런 문자열 정보는 계속 업데이트 되므로,

직접 사용하는것보다는 이미 있는 라이브러리를 사용하고

라이브러리를 업데이트 하는것이 합리적인 방법일겁니다.



그래서 찾아본 결과 가장 적합한 라이브러리는 

<dependency>
<groupId>net.sf.uadetector</groupId>
<artifactId>uadetector-resources</artifactId>
<version>2013.02</version>
</dependency>

이녀석이 적당해 보입니다.

기본적인 사용법은 다음과 같습니다.

-----------------------------------

@Controller
public class HomeController {
@RequestMapping(value = "/", method = RequestMethod.GET)
public String home(Model model, HttpServletRequest request) {
UserAgentStringParser userAgentStringParser = UADetectorServiceFactory.getResourceModuleParser();
model.addAttribute("agent", userAgentStringParser.parse(request.getHeader("User-Agent")));
return "home";
}
}

-----------------------------------

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<html>
<head>
<title>Home</title>
</head>
<body>
<div>${agent.icon}</div>
<div>${agent.name}</div>
<div>${agent.family.name}</div>
<div>${agent.producer}</div>
<div>${agent.producerUrl}</div>
<div>${agent.type.name}</div>
<div>${agent.url}</div>
<div>${agent.versionNumber.major}</div>
<div>${agent.versionNumber.minor}</div>
<div>${agent.versionNumber.extension}</div>
<div>${agent.versionNumber.bugfix}</div>
<div>${agent.operatingSystem.familyName}</div>
<div>${agent.operatingSystem.name}</div>
<div>${agent.operatingSystem.icon}</div>
<div>${agent.operatingSystem.producer}</div>
<div>${agent.operatingSystem.producerUrl}</div>
<div>${agent.operatingSystem.versionNumber.major}</div>
<div>${agent.operatingSystem.versionNumber.minor}</div>
<div>${agent.operatingSystem.versionNumber.extension}</div>
<div>${agent.operatingSystem.versionNumber.bugfix}</div>
</body>
</html>

-----------------------------------

이런식으로 브라우저와 OS정보가 나오게 됩니다.




하지만 매번 페이지가 호출될 때 마다 새로운 UserAgentStringParser 를 생성하는것은 말이 되지 않음으로

일단 이녀석부터 Bean으로 변경했습니다.


-----------------------------------

@Controller
public class HomeController {
@Autowired
UserAgentStringParser userAgentStringParser;
@RequestMapping(value = "/", method = RequestMethod.GET)
public String home(Model model, HttpServletRequest request) {
model.addAttribute("agent", userAgentStringParser.parse(request.getHeader("User-Agent")));
return "home";
}
}

-----------------------------------

<beans:bean class="net.sf.uadetector.service.UADetectorServiceFactory" factory-method="getResourceModuleParser" />

-----------------------------------



그리고 스프링을 쓰면서도 HttpServletRequest 와 같은 low api를 사용하는것은 그리 좋지 않음으로

이녀석을 제거하기 위해서

UserAgent의 인스턴스 (parse메소드의 리턴) 역시도 Bean으로 바꿔보려고 여러가지 삽질을 거듭하였으나

불행하게도 UserAgent는 final class이기 때문에 원활하지 않았습니다.

방법이 있을것도 같았지만 저는 포기하고 request scope의 bean을 별도로 제작하는것으로 합의(?) 했습니다.

-----------------------------------

@Component
public class RequestManager {
@Autowired
HttpServletRequest request;
@Autowired
UserAgentStringParser userAgentStringParser;

public UserAgent getUserAgent(){
return userAgentStringParser.parse(request.getHeader("User-Agent"));
}
}

-----------------------------------

<beans:bean class="jm.test.enoeht_1.RequestManager" scope="request">
<aop:scoped-proxy/>
</beans:bean>

-----------------------------------

public class HomeController {
@Autowired
RequestManager requestManager;
@RequestMapping(value = "/", method = RequestMethod.GET)
public String home(Model model) {
model.addAttribute("agent", requestManager.getUserAgent());
return "home";
}
}
-----------------------------------


request scope의 bean이기 때문에 자체적으로 autowired만으로 HttpServletRequest 를 가져올 수 있습니다.

그러면 컨트롤러나 서비스단에서 굳이 HttpServletRequest같은 클래스에 접근할 필요가 없어졌습니다.



공용빈만 한개 추가되면 충분함으로 실무적용에 큰 무리는 없을것으로 보입니다

물론 더 나아가면 aspect로 처리하는 방법도 있겠으나 굳이 그렇게까지는 할 필요가 없어 보이네요




참고로 위의 작업을 위해서는 다음과 같은 라이브러리가 필요합니다.
   <dependency>
     <groupId>cglib</groupId>
     <artifactId>cglib</artifactId>
     <version>2.2</version>
   </dependency>

또한 스프링 설정파일에서 aop네임스페이스를 추가해야 합니다.


전체 프로젝트 파일을 첨부합니다. 포스트의 오른쪽 상단에 있습니다.

 

728x90
반응형
블로그 이미지

nineDeveloper

안녕하세요 현직 개발자 입니다 ~ 빠르게 변화하는 세상에 뒤쳐지지 않도록 우리모두 열심히 공부합시다 ~! 개발공부는 넘나 재미있는 것~!

,