前言
大家都知道springMVC的使用,我们会少些很多servlet层面的代码,但是随着controller使用多了,就会我们的代码上多出许多RequestMapping注解,
举个例子
一个web文件管理的例子,用户需要这个目录的所有文件,请求到了一个RequestMapping方法,这时我们使用一个类来处理这个这个目录下面的所有文件信息,
我们需要返回每个文件的详细信息,这时如果使用RequestMapping方法就显得有些鸡肋了
- 为什么呢?
- 例如我们需要使用到很多RequestMapping方法来处理客户端每个请求,你想啊,只是一个类似于ls的命令我们就需要创建一个往客户端返回的json对象,当需要实现的功能很多时,这无疑是曾加了许多无用的劳动力,而且会让我们创建很多json对象
好了问题出来了我们来找一个解决办法,问题是什么呢?
1、需要一个只需要实例化一次的json对象方法,2、尽量少些RequestMapping
下面我们先解决第二种问题
如果要少些RequestMapping方法就需要让一个RequestMapping方法来解决客户端的需求,这里就要使用一个策略方法
具体实现方法如何实现呢
嗯,上代码
例如
这个是它的一个接口
public interface CommandExecutorFactory { CommandExecutor get(String commName); }
实现类
@Service("commandExecutorFactory") public class DefaultCommandExecutorFactory implements CommandExecutorFactory{ String _classNamePattern; private Map<String,CommandExecutor>_map= new HashMap<String,CommandExecutor>(); private CommandExecutor _fallbackCommand; @Override public CommandExecutor get(String commName) { if (_map.containsKey(commName)){ return _map.get(commName); } try { String className = String.format(_classNamePattern,commName. substring(0,1).toUpperCase()+commName.substring(1)); return (CommandExecutor) Class.forName(className).newInstance(); } catch (Exception e) { return _fallbackCommand; } } public String get_classNamePattern() { return _classNamePattern; } public void set_classNamePattern(String _classNamePattern) { this._classNamePattern = _classNamePattern; } public Map<String, CommandExecutor> get_map() { return _map; } public void set_map(Map<String, CommandExecutor> _map) { this._map = _map; } public CommandExecutor get_fallbackCommand() { return _fallbackCommand; } public void set_fallbackCommand(CommandExecutor _fallbackCommand) { this._fallbackCommand = _fallbackCommand; } }
如何使用呢
public class CommandController{ private CommandExecutorFactory commandExecutorFactory; private FsUserCommandFactory fsUserCommandFactory; public void connector(HttpServletRequest request, HttpServletResponse response)throws IOException, ServletException{ CommandExecutor executor = null; executor = commandExecutorFactory.get(cmd); if(executor==null){ throw new FsException(String.format("咱不不支持此方法: %s", cmd)); } 。。。。。。。。。。。。。。 } }
通过配置的类的包路径来通过class.forname转换成对象文件,如果报错的话说明是没有此方法的我们返回到前端
这个是不是有点类似Struts的出来方式呢
第二个小问题解决了,这样我们就只需要一个@requestMapping注解就可以
然后先说说第一个问题,如果仅仅只创建一个json对象很多人立刻想到,单例???
what。你在想什么,也可能是我自己这样想的把
其实springmvc这个在上层代码结构里为我们解决了这个办法,所使用的是建造模式的退化版本,相同于模板方法 ,这个退化版本又和模板方法差异’,
来看下UML
建造模式当退化的时候就变成了下列模样
但是呢,还是推荐你去看原文《java与模式》建造模式一篇中详细的介绍
贴张图片
下面用一个比较简单的方法来解决上面的问题
源码是elfinder'的一个实现
我仿照了两个它的两个版本重新修改了下
地址https://github.com/glide-the/dmeck
先附代码,之后详细介绍
controller
@Controller @RequestMapping("connector") public class ConnectorController { @Resource(name = "commandExecutorFactory") private CommandExecutorFactory commandExecutorFactory; @Resource(name ="fsServiceFactory") private FsServiceFactory fsServiceFactory; @RequestMapping public void connector(HttpServletRequest request, final HttpServletResponse response)throws IOException{ /** * 文件上传暂时不做 */ String cmd = request.getParameter("cmd"); CommandExecutor executor = commandExecutorFactory.get(cmd); if(executor==null){ throw new FsException(String.format("unknown command: %s", cmd)); } try { final HttpServletRequest finalRequest = request; executor.execute(new CommandExectionContext() { /** * 总是返回一个factory * @return */ @Override public FsServiceFactory getFsServiceFactory() { return fsServiceFactory; } @Override public HttpServletRequest getRequest() { return finalRequest; } @Override public HttpServletResponse getResponse() { return response; } @Override public ServletContext getServletContext() { return finalRequest.getSession().getServletContext(); } }); } catch (Exception e) { throw new FsException("unknown error", e); } } 。。。。。。。。。。
三个包装接口
CommandExectionContext
public interface CommandExectionContext { FsServiceFactory getFsServiceFactory(); HttpServletRequest getRequest(); HttpServletResponse getResponse(); ServletContext getServletContext(); }
CommandExecutor
/** * 抽象工厂AbstractCommandExecutor的接口 */ public interface CommandExecutor { void execute(CommandExectionContext commandExectionContext) throws Exception; }
CommandExecutorFactory
反射接口 public interface CommandExecutorFactory { CommandExecutor get (String commandName); }
AbstractCommandExecutor
/** * 抽象工厂 */ public abstract class AbstractCommandExecutor implements CommandExecutor { private static final String CMD_TMB_TARGET = "?cmd=tmb&target=%s"; private Map<String, Object> map = new HashMap<>(); @Override public void execute(CommandExectionContext ctx) throws Exception { FsService fileService = ctx.getFsServiceFactory().getFileService(ctx.getRequest(),ctx.getServletContext()); execute(fileService,ctx.getRequest(),ctx.getResponse(),ctx.getServletContext()); } public abstract void execute(FsService fileService, HttpServletRequest request, HttpServletResponse response, ServletContext servletContext)throws Exception; -------------------------
AbstractorJsonCommandExecutor
/** * 抽象工厂装饰类 */ public abstract class AbstractorJsonCommandExecutor extends AbstractCommandExecutor { @Override final public void execute(FsService fsService, HttpServletRequest request, HttpServletResponse response, ServletContext servletContext) throws Exception { JSONObject json = new JSONObject(); try { execute(fsService, request, servletContext, json); } catch (ErrorException e) { /** * 自定义异常处理 */ if (e.getArgs() == null || e.getArgs().length == 0) { json.put("error", e.getError()); } else { JSONArray errors = new JSONArray(); errors.put(e.getError()); for (String s : e.getArgs()) { errors.put(s); } json.put("error", errors); } } catch (Exception e) { json.put("error", e.getMessage()); } finally { response.setContentType("text/html;charset= UTF-8"); PrintWriter writer = response.getWriter(); json.write(writer); System.out.println(json); writer.flush(); writer.close(); } } protected abstract void execute(FsService fsService, HttpServletRequest request, ServletContext servletContext, JSONObject json) throws Exception; }
DefaultCommandExecutorFactory
反射实现 public class DefaultCommandExecutorFactory implements CommandExecutorFactory { String _classNamePattern; private Map<String,CommandExecutor>_map= new HashMap<String,CommandExecutor>(); private CommandExecutor _fallbackCommand; @Override public CommandExecutor get(String commandName) { if (_map.containsKey(commandName)){ return _map.get(commandName); } try { String className = String.format(_classNamePattern,commandName. substring(0,1).toUpperCase()+commandName.substring(1)); return (CommandExecutor) Class.forName(className).newInstance(); } catch (Exception e) { return _fallbackCommand; } }
OpenCommandExecutor
具体执行器 public class OpenCommandExecutor extends AbstractorJsonCommandExecutor implements CommandExecutor{ @Override protected void execute(FsService fsService, HttpServletRequest request, ServletContext servletContext, JSONObject json) throws Exception { boolean init = request.getParameter(ElFinderConstants.ELFINDER_PARAMETER_INIT) !=null; boolean tree = request.getParameter(ElFinderConstants.ELFINDER_PARAMETER_TREE) !=null; String target = request.getParameter(ElFinderConstants.ELFINDER_PARAMETER_TARGET); Map<String ,TargetEx> files= new LinkedHashMap<String, TargetEx>(); if (init){ json.put(ElFinderConstants.ELFINDER_PARAMETER_API,2.1); json.put(ElFinderConstants.ELFINDER_PARAMETER_NETDRIVERS,new Object[0]); } if (tree){ for (Volume v : fsService.getVolumes()) { TargetEx root = new TargetEx(v.getRoot(), fsService); files.put(root.getHash(),root); addSubFolders(files,root); } } TargetEx cwd = finderCwd(fsService, target); files.put(cwd.getHash(),cwd); addChildren(files,cwd); json.put(ElFinderConstants.ELFINDER_PARAMETER_FILES,buildJsonFilesArray(request,files.values())); json.put(ElFinderConstants.ELFINDER_PARAMETER_CWD,getTargetInfo(request,cwd)); json.put(ElFinderConstants.ELFINDER_PARAMETER_OPTIONS,getOptions(cwd)); } }