servlet仿struts参数注入
在struts中可以在action中声明一个成员变量如Game game和Date date,接口访问时可以通过http://xxx.com/xxx/addGameScore?game.gameID=xx&&game.score=10&&date=xxx的方式
直接将参数注入。用servlet模拟struts的参数注入,可以使用一个servlet对应一个接口集,如只创建一个servlet就可以处理所有关于玩家Player相关的接口
代码如下:
创建一个PlayerServlet
1 /** 2 * 玩家相关入口 3 * 4 */ 5 public class PlayerServlet extends HttpServlet { 6 private static final long serialVersionUID = -5269133950459049991L; 7 8 public PlayerServlet() { 9 super(); 10 } 11 12 public void destroy() { 13 super.destroy(); 14 } 15 16 public void doGet(HttpServletRequest request, HttpServletResponse response) 17 throws ServletException, IOException { 18 handleService(request,response); 19 } 20 21 public void doPost(HttpServletRequest request, HttpServletResponse response) 22 throws ServletException, IOException { 23 handleService(request,response); 24 } 25 //提交给servlet的参数中必须包含target参数,值为对应action的public方法 26 //处理业务逻辑 27 private void handleService(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException{ 28 PlayerAction playerAction = new PlayerAction(); 29 ServletUtil.handleServletRequest(playerAction, request, response); 30 playerAction = null; 31 } 32 33 public void init() throws ServletException { 34 35 } 36 }
如struts一样,需要一个PlayerAction,里面的成员变量为注入的参数,公共方法为对应的逻辑方法
创建PlayerAction
1 /** 2 * 玩家相关Action 3 */ 4 public class PlayerAction extends BaseAction{ 5 6 private Integer playerID; 7 8 private String playerNickName; 9 10 private Player player; 11 12 private IPlayerService playerService; 13 14 public PlayerAction(){ 15 this.playerService = new PlayerServiceImpl(); 16 } 17 /**玩家登陆*/ 18 public void playerLogin(){ 19 System.out.println("playerAccount:"+player.getPlayerAccount()); 20 System.out.println("playerPassword:"+player.getPlayerPassword()); 21 } 22 /**查询玩家信息*/ 23 public void findPlayer(){ 24 try { 25 response.getWriter().write("玩家ID:"+playerID+",昵称:"+playerNickName); 26 } catch (Exception e) { 27 e.printStackTrace(); 28 } 29 } 30 31 //===========相关get和set方法====================================== 32 public void setPlayerID(Integer playerID) { 33 this.playerID = playerID; 34 } 35 36 public void setPlayerNickName(String playerNickName) { 37 this.playerNickName = playerNickName; 38 } 39 40 public void setPlayer(Player player) { 41 this.player = player; 42 } 43 public Player getPlayer() { 44 return player; 45 } 46 }
核心servletUtil,使用java反射注入参数
1 /** 2 * servlet工具类,提供servlet向action自动注入参数的相关工具 3 * 4 */ 5 public class ServletUtil { 6 /** 7 * 处理servlet请求,完成request、response和其它参数注入 8 * @param baseAction 9 * @param request 10 * @param response 11 */ 12 @SuppressWarnings({ "unchecked", "rawtypes" }) 13 public static void handleServletRequest(BaseAction baseAction, 14 HttpServletRequest request,HttpServletResponse response){ 15 try { 16 //注入request和response 17 requestAndResponseInject(baseAction, request, response); 18 Map<String, String[]> argsMap = request.getParameterMap();//获取提交参数 19 String targetMethod = request.getParameter("target");//获取调用目标方法名 20 Iterator<Entry<String, String[]>> iterator= argsMap.entrySet().iterator(); 21 while(iterator.hasNext()){ 22 Entry<String, String[]> entry = iterator.next(); 23 String key = entry.getKey(); 24 if(!key.equals("target")){ 25 ServletUtil.propertyInject(key,entry.getValue(),baseAction);//注入参数 26 } 27 } 28 Class actionClass = baseAction.getClass(); 29 Method method = actionClass.getDeclaredMethod(targetMethod); 30 method.invoke(baseAction);//调用目标方法 31 } catch (Exception e) { 32 e.printStackTrace(); 33 } 34 } 35 36 /** 37 * 向目标action注入request和response对象 38 * @param target 目标action 39 * @param request 40 * @param response 41 * @throws Exception 42 */ 43 @SuppressWarnings("rawtypes") 44 private static void requestAndResponseInject(Object target, 45 HttpServletRequest request,HttpServletResponse response) throws Exception{ 46 Class actionClass = target.getClass(); 47 Field[] fields = actionClass.getFields(); 48 for(Field f:fields){ 49 if(HttpServletRequest.class.isAssignableFrom(f.getType())){ 50 f.setAccessible(true); 51 f.set(target, request); 52 }else if(HttpServletResponse.class.isAssignableFrom(f.getType())){ 53 f.setAccessible(true); 54 f.set(target, response); 55 } 56 } 57 } 58 /** 59 * 属性注入,支持基本类型、时间和对象,List和Set泛型只支持基本类型 60 * @param key 属性键 61 * @param value 值 62 * @param target 注入目标 63 * @throws Exception 64 */ 65 @SuppressWarnings({ "rawtypes", "unchecked" }) 66 public static void propertyInject(String key,String[] value,Object target)throws Exception{ 67 Class actionType = target.getClass(); 68 //非自定义复合对象 69 if(!key.contains(".")){ 70 Field field = actionType.getDeclaredField(key); 71 Class fieldType = field.getType(); 72 //获取setXXX方法 73 Method method=actionType.getDeclaredMethod("set"+key.substring(0, 1).toUpperCase()+key.substring(1),fieldType); 74 if(List.class.isAssignableFrom(fieldType)){//List泛型 75 List<Object> list = new ArrayList<Object>(); 76 //获取泛型类型 77 Type[] argType = ((ParameterizedType)field.getGenericType()).getActualTypeArguments(); 78 for(int i=0;i<value.length;i++){ 79 list.add(generateNormalValue((Class)argType[0],value[i]));//填入List 80 } 81 method.invoke(target,list);//注入List 82 }else if(Set.class.isAssignableFrom(fieldType)){ 83 Set<Object> set = new HashSet<Object>(); 84 Type[] argType = ((ParameterizedType)field.getGenericType()).getActualTypeArguments(); 85 for(int i=0;i<value.length;i++){ 86 set.add(generateNormalValue((Class)argType[0],value[i])); 87 } 88 method.invoke(target,set); 89 }else{ 90 method.invoke(target,generateNormalValue(fieldType,value[0]));//基本类型 91 } 92 }else{//自定义复合对象属性 93 generateObjectValue(key,value[0],target); 94 } 95 } 96 97 /** 98 * 生成基本类型值 99 * @param fieldType 字段类型 100 * @param value 值 101 * @return 102 * @throws Exception 103 */ 104 @SuppressWarnings({ "rawtypes", "unchecked" }) 105 private static Object generateNormalValue(Class fieldType,Object value)throws Exception{ 106 //如果为时间类型,转换时间 107 if(Date.class.isAssignableFrom(fieldType)){ 108 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); 109 Date date = sdf.parse(value.toString()); 110 return date; 111 }else{//Integer、String、Long等封装类型 112 //获取单参构造函数 113 Constructor<String> ctor = fieldType.getConstructor(String.class); 114 return ctor.newInstance(value); 115 } 116 } 117 118 /** 119 * 生成自定义对象值 120 * @param key 属性键 121 * @param value 值 122 * @param target 注入目标 123 * @throws Exception 124 */ 125 @SuppressWarnings({ "rawtypes", "unchecked" }) 126 private static void generateObjectValue(String key,Object value,Object target)throws Exception{ 127 String subKey = key; 128 Class targetType = target.getClass(); 129 String[] keys = key.split("\\.");//分割键 130 subKey = keys[0]; 131 Field field = targetType.getDeclaredField(subKey); 132 Class fieldType = field.getType(); 133 //获取setXXX方法 134 Method setMethod=targetType.getDeclaredMethod("set"+subKey.substring(0, 1).toUpperCase()+subKey.substring(1),fieldType); 135 if(keys.length>1){ 136 Constructor<String> ctor = fieldType.getConstructor();//获取默认构造函数 137 //获取getXXX方法 138 Method getMethod=targetType.getDeclaredMethod("get"+subKey.substring(0, 1).toUpperCase()+subKey.substring(1)); 139 Object subTarget = getMethod.invoke(target); 140 if(null==subTarget){ 141 subTarget = ctor.newInstance();//调用无参构造函数 142 } 143 setMethod.invoke(target, subTarget);//对象注入 144 generateObjectValue((key.split("\\.", 2))[1],value,subTarget);//子属性还是对象,递归注入 145 }else{ 146 setMethod.invoke(target,generateNormalValue(fieldType,value));//子属性为基本类型 147 } 148 } 149 }
代码中的BaseAction就是一个普通的类,包含了request和response成员变量和相关的数据输出方法
1 /** 2 * action基类,包含request和response信息及数据输出方法 3 * 4 */ 5 public class BaseAction { 6 7 public HttpServletRequest request; 8 9 public HttpServletResponse response; 10 //==数据输出方法== 11 //.... 12 }
web.xml
1 <!-- 玩家相关请求入口 --> 2 <servlet-name>PlayerServlet</servlet-name> 3 <servlet-class>com.xxx.servlet.PlayerServlet</servlet-class> 4 </servlet> 5 <servlet-mapping> 6 <servlet-name>PlayerServlet</servlet-name> 7 <url-pattern>/player</url-pattern> 8 </servlet-mapping>
调用方式:
调用登陆方法:http://www.xxx.com/项目根/player?target=playerLogin&player.playerAccount=xx&player.playerPassword=xxx
调用查询方法:http://www.xxx.com/项目根/player?target=findPlayer&player.playerID=xx