其实大家在工作的时候,一般很少涉及框架大改的情况,除非是一个值得重视与长期发展的项目,碰巧我遇到了一个比较重要的项目,由于项目的初次搭建的时候欠缺很多方法的考虑,使用了比较旧的架构:Spring+Struts2+Hibernate+MyBatis,这个框架也有一些优点,比如Hibernate+MyBatis可以同时使用,而且还共用了数据源,也不影响事务的切面。由于Spring的发展比Struts2的发展快以及各项优点(此处不多说),加上SpringBoot、SpringCloud的出现,大多数程序员都倾向于使用SpringMVC而不是Struts2MVC,因此,考虑到公司大项目的发展,项目计划第一步由Struts2MVC转换成SpringMVC(Spring版本不变,还是3版本),第二步升级Spring版本(由版本3升级版本4,尽量做到无配置文件),第三步转为SpringBoot项目或者SpringCloud微服务(模块分割),此处由有多年架构方面经验的我来完成项目计划的第一步(由Struts2MVC转换成SpringMVC)
1、修改pom文件:
去掉struts2的相关依赖:比如:struts2-core、struts2-convention-plugin、struts2-junit-plugin、struts2-json-plugin、struts2-spring-plugin等等包含struts2的依赖包
由于我的项目有appfuse-web的依赖,所以不需要添加spring-webmvc的依赖,如果你的项目没有SpringMVC相关依赖,请添加
2、修改web.xml文件:
(1)去掉Struts2的filter和filter-mapping以及删除struts.xml文件(建议备份)
struts
org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter
config
struts-default.xml,struts-plugin.xml,conf/struts/struts.xml
struts
/*
REQUEST
FORWARD
(2)加上springMVC的servlet和servlet-mapping(需要注意url-pattern的值,文章下面有其他说明)
springMVC
org.springframework.web.servlet.DispatcherServlet
contextConfigLocation
classpath:conf/spring/spring-mvc.xml
1
springMVC
/
3、在classpath:conf/spring/下面添加spring-mvc.xml(Json转换器暂时使用Jackson,而MyExceptionMappingInterceptor是本项目的全局异常类,PrivilegeInterceptor是本项目的拦截器)
text/html;charset=UTF-8
4、由于Controller注解在上面的xml已扫描,所以在applicationContext-service.xml去掉Controller注解的扫描(这个xml文件原有事务管理器与aop切面等配置,根据自己项目寻找自己的xml文件)【注:至于Controller注解扫描为什么与其他注解分开,这个问题请自行去了解一下SpringMVC的启动原理】
修改前:
修改后:
5、拦截器调整
(1)调整全局异常拦截器MyExceptionMappingInterceptor:由继承Struts2的ExceptionMappingInterceptor换成继承SpringMVC的ExceptionHandlerExceptionResolver,由于继承类不同,方法也不同,返回类型不同,稍微理解一下进行了更改如下:
public class MyExceptionMappingInterceptor extends ExceptionMappingInterceptor {
private static final long serialVersionUID = -1L;
private static final Logger logger = LoggerFactory.getLogger(MyExceptionMappingInterceptor.class);
@Override
public String intercept(ActionInvocation invocation) throws Exception {
String result = null;
try {
result = invocation.invoke();
} catch (GeneralException ex) {
result = handleException(ex, invocation);
} catch (UnauthorizedAccessException ex) {
result = handleException(ex, invocation);
} catch (BusinessException ex) {
result = handleException(ex, invocation);
} catch (IncorrectResultSizeDataAccessException ex) {
result = handleException(new BusinessException(ex, "数据库查询唯一记录时返回了2条及以上记录!"), invocation);
} catch (DataAccessException ex) {
result = handleException(new BusinessException(ex, "数据库操作失败!"), invocation);
} catch (NullPointerException ex) {
result = handleException(new BusinessException(ex, "调用了未经初始化的对象或者是不存在的对象!"), invocation);
} catch (IOException ex) {
result = handleException(new BusinessException(ex, "IO异常!"), invocation);
} catch (ClassNotFoundException ex) {
result = handleException(new BusinessException(ex, "指定的类不存在!"), invocation);
} catch (ArithmeticException ex) {
result = handleException(new BusinessException(ex, "数学运算异常!"), invocation);
} catch (ArrayIndexOutOfBoundsException ex) {
result = handleException(new BusinessException(ex, "数组下标越界!"), invocation);
} catch (IllegalArgumentException ex) {
result = handleException(new BusinessException(ex, "方法的参数错误!"), invocation);
} catch (ClassCastException ex) {
result = handleException(new BusinessException(ex, "类型强制转换错误!"), invocation);
} catch (SecurityException ex) {
result = handleException(new BusinessException(ex, "违背安全原则异常!"), invocation);
} catch (SQLException ex) {
result = handleException(new BusinessException(ex, "SQL语句出错!"), invocation);
// } catch (QuerySyntaxException ex) {
// result = handleException(new BusinessException(ex, "HQL语句出错!"), invocation);
} catch (NoSuchMethodError ex) {
result = handleException(new BusinessException(ex, "请求的方法末找到!"), invocation);
} catch (NoSuchMethodException ex) {
result = handleException(new BusinessException(ex, "请求的方法末找到!"), invocation);
} catch (InternalError ex) {
result = handleException(new BusinessException(ex, "Java虚拟机发生了内部错误!"), invocation);
} catch (Exception ex) {
result = handleException(new BusinessException(ex, "程序内部错误,操作失败!"), invocation);
}
return result;
}
/**
* 处理异常并路由到需要的页面
* 与struts.xml中的global-exception-mappings配置匹配
* @param e
* 抛出的异常
* @param invocation
* 上下文环境
* @return
*/
private String handleException(RuntimeException e, ActionInvocation invocation) {
ActionContext ctx = invocation.getInvocationContext();
HttpServletRequest request = (HttpServletRequest)ctx.get(ServletActionContext.HTTP_REQUEST);
HttpServletResponse response = (HttpServletResponse)ctx.get(ServletActionContext.HTTP_RESPONSE);
// 记录错误日志
writeErrorLog(e, invocation);
// 统一处理下载请求的异常
String contentType = response.getContentType();
if(StringUtils.equalsIgnoreCase(contentType, "application/x-download")){
response.setCharacterEncoding("utf-8");
PrintWriter out = null;
try {
out = response.getWriter();
} catch (IOException e1) {
logger.error(e1.getMessage(), e1);
}
out.print("");
out.close();
}
// ajax请求异常,则返回友好提示
String type = request.getHeader("X-Requested-With");
if ("XMLHttpRequest".equalsIgnoreCase(type)) {
ActionResult actionResult = new ActionResult(true);
actionResult.setErrorMsg(e.getMessage(), e);
AjaxUtil.renderJSON(response, JsonUtil.bean2json(actionResult));
return null;
}else{
handleLogging(e);
List exceptionMappings = invocation.getProxy().getConfig().getExceptionMappings();
// 根据异常的类型查找对应的路由
ExceptionMappingConfig mappedResult = this.findMappingFromExceptions(exceptionMappings, e);
if (mappedResult != null) {
String result = mappedResult.getResult();
publishException(invocation, new ExceptionHolder(e));
return result;
} else {
throw e;
}
}
}
/**
* 记录错误日志
* @param e
* @param invocation
*/
private void writeErrorLog(RuntimeException e, ActionInvocation invocation) {
try {
ActionProxy proxy = invocation.getProxy();
String module = StringUtils.replace(proxy.getNamespace(), "/", "");
String subModule = proxy.getActionName();
// 请求参数
Map map = invocation.getInvocationContext().getParameters();
String message = "提交的参数:" + AppUtils.getRequestParameterStr(map);
SysLoginUser loginUser = AppUtils.getSysLoginUser();
String userId = loginUser != null ? loginUser.getSurId() : "";
ErrorLogWriter.doLogging(message, e, module, subModule, userId);
}catch (Exception ex){
logger.error("写错误日志异常:" + e.getMessage(), ex);
}
}
}
修改后:
public class MyExceptionMappingInterceptor extends ExceptionHandlerExceptionResolver {
private static final long serialVersionUID = -1L;
private static final Logger logger = LoggerFactory.getLogger(MyExceptionMappingInterceptor.class);
@Override
public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,
Object o, Exception e) {
RuntimeException runtimeException = null;
if (e instanceof GeneralException) {
runtimeException = (RuntimeException) e;
} else if (e instanceof UnauthorizedAccessException) {
runtimeException = (RuntimeException) e;
} else if (e instanceof BusinessException) {
runtimeException = (RuntimeException) e;
} else if (e instanceof IncorrectResultSizeDataAccessException) {
runtimeException = new BusinessException(e, "数据库查询唯一记录时返回了2条及以上记录!");
} else if (e instanceof DataAccessException) {
runtimeException = new BusinessException(e, "数据库操作失败!");
} else if (e instanceof NullPointerException) {
runtimeException = new BusinessException(e, "调用了未经初始化的对象或者是不存在的对象!");
} else if (e instanceof IOException) {
runtimeException = new BusinessException(e, "IO异常!");
} else if (e instanceof ClassNotFoundException) {
runtimeException = new BusinessException(e, "指定的类不存在!");
} else if (e instanceof ArithmeticException) {
runtimeException = new BusinessException(e, "数学运算异常!");
} else if (e instanceof ArrayIndexOutOfBoundsException) {
runtimeException = new BusinessException(e, "数组下标越界!");
} else if (e instanceof IllegalArgumentException) {
runtimeException = new BusinessException(e, "方法的参数错误!");
} else if (e instanceof ClassCastException) {
runtimeException = new BusinessException(e, "类型强制转换错误!");
} else if (e instanceof SecurityException) {
runtimeException = new BusinessException(e, "违背安全原则异常!");
} else if (e instanceof SQLException) {
runtimeException = new BusinessException(e, "SQL语句出错!");
// } else if (e instanceof NoSuchMethodError) {
} else if (e instanceof NoSuchMethodException) {
runtimeException = new BusinessException(e, "请求的方法末找到!");
// } else if (e instanceof InternalError) {
} else if (e instanceof InternalException) {
runtimeException = new BusinessException(e, "Java虚拟机发生了内部错误!");
} else if (e instanceof Exception) {
runtimeException = new BusinessException(e, "程序内部错误,操作失败!");
}
return handleException(runtimeException, httpServletRequest, httpServletResponse, o);
}
/**
* 处理异常并路由到需要的页面
*
* @param e 抛出的异常
* @param httpServletRequest
* @param httpServletResponse @return
* @param o
*/
private ModelAndView handleException(RuntimeException e, HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) {
// 记录错误日志
writeErrorLog(e, httpServletRequest, httpServletResponse, o);
// 统一处理下载请求的异常
String contentType = httpServletResponse.getContentType();
if (StringUtils.equalsIgnoreCase(contentType, "application/x-download")) {
httpServletResponse.setCharacterEncoding("utf-8");
PrintWriter out = null;
try {
out = httpServletResponse.getWriter();
} catch (IOException e1) {
logger.error(e1.getMessage(), e1);
}
out.print("");
out.close();
}
ModelAndView modelAndView = null;
// ajax请求异常,则返回友好提示
String type = httpServletRequest.getHeader("X-Requested-With");
if ("XMLHttpRequest".equalsIgnoreCase(type)) {
ActionResult actionResult = new ActionResult(true);
actionResult.setErrorMsg(e.getMessage(), e);
AjaxUtil.renderJSON(httpServletResponse, JsonUtil.bean2json(actionResult));
} else {
if (e instanceof GeneralException) {
modelAndView = new ModelAndView("/error.jsp");
} else if (e instanceof UnauthorizedAccessException) {
modelAndView = new ModelAndView("/unauth.jsp");
} else if (e instanceof BusinessException) {
modelAndView = new ModelAndView("/error.jsp");
}
}
return modelAndView;
}
/**
* 记录错误日志
*
* @param e
* @param httpServletRequest
* @param httpServletResponse
* @param o
*/
private void writeErrorLog(RuntimeException e, HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) {
try {
Object handler = null;
if (o instanceof HandlerMethod) {
HandlerMethod handlerMethod = (HandlerMethod) o;
handler = handlerMethod.getBean();
}
// String module = StringUtils.replace(proxy.getNamespace(), "/", "");
StringBuffer url = httpServletRequest.getRequestURL();
String module = url.delete(url.length() - httpServletRequest.getRequestURI().length(), url.length()).append("/").toString();
String subModule = handler.getClass().getName();
// 请求参数
Map map = httpServletRequest.getParameterMap();
String message = "提交的参数:" + AppUtils.getRequestParameterStr(map);
SysLoginUser loginUser = AppUtils.getSysLoginUser();
String userId = loginUser != null ? loginUser.getSurId() : "";
ErrorLogWriter.doLogging(message, e, module, subModule, userId);
} catch (Exception ex) {
logger.error("写错误日志异常:" + e.getMessage(), ex);
}
}
}
(2)调整日志拦截器LogInterceptor:由继承AbstractInterceptor改为实现HandlerInterceptor接口
需要注意的是: AbstractInterceptor的intercept方法里面的result = invocation.invoke();这句代码为分割点,分割点前的代码放进HandlerInterceptor的preHandle方法里面,而分割点后的代码放进postHandle方法里面,至于try catch分割点的代码只能迁移到全局异常类里操作(此处省略掉),至于为什么要这样改,我也不多说了,请了解一下Struts2的拦截器和Spring的拦截器
修改前:
public class LogInterceptor extends ExceptionMappingInterceptor {
private static final long serialVersionUID = -5260452584263751123L;
private static final Logger logger = LoggerFactory.getLogger(LogInterceptor.class);
private static final String ENTER = "->>>开始调用: ";
private static final String EXIT = "<<<-结束调用: ";
private final static String USER_NAME = "userName";
private final static String THREADINFO = "ThreadInfo";
private ThreadLocal depth = new ThreadLocal() {
@Override
protected Integer initialValue() {
return 0;
}
};
public String intercept(ActionInvocation invocation) throws Exception {
long startTime = System.currentTimeMillis();
Map session = invocation.getInvocationContext().getSession();
if (session != null) {
SysLoginUser loginUser = (SysLoginUser) session.get(Constants.SYSLOGINUSER_IN_SESSION);
if (loginUser != null) {
Thread current = Thread.currentThread();
MDC.put(USER_NAME, loginUser.getSurName());
MDC.put(THREADINFO, "ThreadID:" + current.getId());
}
}
//构建StringBuffer
ActionProxy proxy = invocation.getProxy();
String method = proxy.getMethod();
StringBuilder sb = new StringBuilder();
int d = depth.get();
for (int i = 0; i < d; i++) {
sb.append(' ');
}
sb.append(ENTER);
sb.append(proxy.getActionName());
//可以打印请求参数(登陆请求不打印参数)
Map map = invocation.getInvocationContext().getParameters();
//参数非空则打印参数
if (map.size() != 0) {
sb.append('(');
for (String key : map.keySet()) {
if (!"sfUser.sfuNameSpelling".equals(key)) { // 不打印协同的token
sb.append('[');
sb.append(key);
sb.append('=');
sb.append(((String[]) map.get(key))[0].toString());
sb.append("]");
}
}
sb.append(')');
}
//在方法调用之前打印方法名
logger.info(sb.toString());
depth.set(++d);
String result = "";
try {
//继续调用拦截器
result = invocation.invoke();
} catch (Throwable t) {
depth.set(--d);
sb.replace(d, d + ENTER.length(), EXIT);
logger.info(sb.toString());
throw t;
}
depth.set(--d);
//替换-> 为 <-
sb.replace(d, d + ENTER.length(), EXIT);
//在方法调用之后打印方法名
logger.info(sb.toString());
//在方法调用之后打印该请求的花费时间
logger.info("[方法:" + proxy.getActionName() + "() 调用时间] = " + (System.currentTimeMillis() - startTime) + " 毫秒!");
//清除用户名
MDC.remove(USER_NAME);
return result;
}
}
修改后:
public class LogInterceptor implements HandlerInterceptor {
private static final long serialVersionUID = -5260452584263751123L;
private static final Logger logger = LoggerFactory.getLogger(LogInterceptor.class);
private static final String ENTER = "->>>开始调用: ";
private static final String EXIT = "<<<-结束调用: ";
private final static String USER_NAME = "userName";
private final static String THREADINFO = "ThreadInfo";
private ThreadLocal startTime = new ThreadLocal() {
@Override
protected Long initialValue() {
return System.currentTimeMillis();
}
};
private ThreadLocal depth = new ThreadLocal() {
@Override
protected Integer initialValue() {
return 0;
}
};
private ThreadLocal actionName = new ThreadLocal();
private ThreadLocal stringBuilder = new ThreadLocal(){
@Override
protected StringBuilder initialValue() {
return new StringBuilder();
}
};
@Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
if (o instanceof HandlerMethod) {
HandlerMethod h = (HandlerMethod) o;
actionName.set(h.getBean().getClass().getName());
}
HttpSession session = httpServletRequest.getSession();
if (session != null) {
SysLoginUser loginUser = (SysLoginUser) session.getAttribute(Constants.SYSLOGINUSER_IN_SESSION);
if (loginUser != null) {
Thread current = Thread.currentThread();
MDC.put(USER_NAME, loginUser.getSurName());
MDC.put(THREADINFO, "ThreadID:" + current.getId());
}
}
//构建StringBuffer
StringBuilder sb = stringBuilder.get();
int d = depth.get();
for (int i = 0; i < d; i++) {
sb.append(' ');
}
sb.append(ENTER);
sb.append(actionName.get());
//可以打印请求参数(登陆请求不打印参数)
Map map = httpServletRequest.getParameterMap();
//参数非空则打印参数
if (map.size() != 0) {
sb.append('(');
for (String key : map.keySet()) {
if (!"sfUser.sfuNameSpelling".equals(key)) { // 不打印协同的token
sb.append('[');
sb.append(key);
sb.append('=');
sb.append(((String[]) map.get(key))[0].toString());
sb.append("]");
}
}
sb.append(')');
}
//在方法调用之前打印方法名
logger.info(sb.toString());
depth.set(++d);
stringBuilder.set(sb);
return true;
}
@Override
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
int d = depth.get();
depth.set(--d);
StringBuilder sb = stringBuilder.get();
//替换-> 为 <-
sb.replace(d, d + ENTER.length(), EXIT);
stringBuilder.set(sb);
//在方法调用之后打印方法名
logger.info(sb.toString());
//在方法调用之后打印该请求的花费时间
logger.info("[方法:" + actionName.get() + "() 调用时间] = " + (System.currentTimeMillis() - startTime.get()) + " 毫秒!");
//清除用户名
MDC.remove(USER_NAME);
}
@Override
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
}
}
(3)同理调整权限拦截器PrivilegeInterceptor(这个代码比较简单,可不看):由继承AbstractInterceptor改为实现HandlerInterceptor接口
修改前:(只显示部分代码)
public class PrivilegeInterceptor extends AbstractInterceptor {
private static final long serialVersionUID = 8887312034961459123L;
private static final Logger logger = LoggerFactory.getLogger(PrivilegeInterceptor.class);
@Override
public String intercept(ActionInvocation invocation) throws Exception {
String result = "";
try {
ActionContext ctx = invocation.getInvocationContext();
HttpServletRequest request = (HttpServletRequest) ctx.get(ServletActionContext.HTTP_REQUEST);
SysLoginUser loginUser = (SysLoginUser) request.getSession().getAttribute(Constants.SYSLOGINUSER_IN_SESSION);
if (loginUser != null) {
// 检查权限,没有权限就抛异常
checkPrivilege(request, loginUser);
}
// 继续调用拦截器
result = invocation.invoke();
} catch (Throwable t) {
throw t;
}
return result;
}
}
修改后:
public class PrivilegeInterceptor implements HandlerInterceptor {
private static final long serialVersionUID = 8887312034961459123L;
private static final Logger logger = LoggerFactory.getLogger(PrivilegeInterceptor.class);
@Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
try {
SysLoginUser loginUser = (SysLoginUser) httpServletRequest.getSession().getAttribute(Constants.SYSLOGINUSER_IN_SESSION);
if (loginUser != null) {
// 检查权限,没有权限就抛异常
checkPrivilege(httpServletRequest, loginUser);
}
} catch (Throwable t) {
throw t;
}
return true;
}
@Override
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
}
}
6、由于本项目的过滤器都是使用javax.servlet.Filter,所以不需要更改filter代码
7、全局搜索ServletActionContext(这是Struts的上下文)
本项目把ServletActionContext.getResponse()替换成
((ServletWebRequest) RequestContextHolder.getRequestAttributes()).getResponse()
把ServletActionContext.getRequest()替换成
((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest()
8、全局搜索sessionMap.get替换成sessionMap.getAttribute
9、把Struts2接收附件的MultiPartRequestWrapper替换成Spring的MultipartHttpServletRequest,替换后使用的语法不同,此处不粘贴详细代码了(上传附件建议在controller的方法里面加上参数@RequestParam("upfile") MultipartFile[] files来接收文件,本项目用ajaxfileupload.js插件上传,框架换了后这个js也有小调整)
10、页面jsp调整:去掉<%@ taglib prefix="s" uri="/struts-tags"%>以及调整s开头的标签如下:
(1)
(2)
(3)
(4)
(5)
(6)cssStyle替换成style
11、那么重点来了,最痛苦的就是所有的url请求地址的更换,对于一般的小项目来说直接替换url,但是本项目的代码太多了,于是,找到了一个很好的办法,便是使用了urlrewrite实现url重写,把.do为后缀的url进行重写,这样就不用更换所有url了
(1)在web.xml添加filter和filter-mapping,注意filter的顺序,在该filter之前的filter处理的url还是有.do的,之后的filter则是被转换后的url
UrlRewriteFilter
org.tuckey.web.filters.urlrewrite.UrlRewriteFilter
logLevel
WARN
UrlRewriteFilter
*.do
REQUEST
FORWARD
(2)在WEB-INF下添加urlrewrite.xml(请根据自身项目调整from和to的匹配)
forward(转发模式)传参
example:/a/b_c.do->/a/b/c
/([A-Za-z0-9]+)/([A-Za-z0-9]+)_([A-Za-z0-9]+).do
/$1/$2/$3
12、url调整好了,就准备开始改另一个重点,Controller层(或Action层)的代码调整
为了方便代码的更改,我自己写了一个工具类,获取获取controller类以及方法的RequestMapping注解的值
public class BaseActionUtil {
/**
* 获取controller的RequestMapping注解的值
*
* @return
*/
public static String getActionRequestMapping(Class clazz) {
String result = "";
RequestMapping requestMapping = (RequestMapping) clazz.getAnnotation(RequestMapping.class);
if (requestMapping != null) {
String[] requestMappingValue = requestMapping.value();
if (requestMappingValue.length > 0) {
result = requestMappingValue[0];
}
}
return result;
}
/**
* 获取controller下的方法的RequestMapping注解的值
*
* @return
*/
public static Map getMethodRequestMapping(Class clazz) {
Map methodRequestMappingValue = new HashMap();
Method[] methods = clazz.getMethods();
for (Method method : methods) {
RequestMapping requestMapping = method.getAnnotation(RequestMapping.class);
if (requestMapping != null) {
String[] requestMappingValue = requestMapping.value();
if (requestMappingValue.length > 0) {
methodRequestMappingValue.put(method.getName(), requestMappingValue[0]);
}
}
}
return methodRequestMappingValue;
}
}
本项目Controller层(或Action层)的代码调整步骤:
(1)类的调整
a、去掉@Scope注解
b、加上@RequestMapping注解(值:根据请求url来写)
c、去掉BaseAction继承(本项目有抽取过父类,所以不需要继承了)
d、加上2个私有变量:
private String actionRequestMappingValue;
private Map
e、加上初始化方法(注意修改:aaa.class为当前类)
@PostConstruct
public void init() {
this.actionRequestMappingValue = BaseActionUtil.getActionRequestMapping(aaa.class);
this.methodRequestMappingValue = BaseActionUtil.getMethodRequestMapping(aaa.class);
}
(2)方法调整:
a、普通方法(返回jsp路径的,非ajax)
(a)加上@RequestMapping注解(值:根据请求url来写, 这里一般都是跟方法名一致,除了strust.xml中的某些特殊url])
(b)返回类型都是String
(c)除了strust.xml特殊url,返回路径都是return actionRequestMappingValue + methodRequestMappingValue.get("aaa");(注意修改:aaa为当前方法的名),因此这里就可以直接返回controller类RequestMapping注解的值+方法的RequestMapping注解的值,刚刚好就是jsp在项目中的路径。
b、ajax方法
(a)加上注解 @RequestMapping、@ResponseBody
(b)返回类型基本为ActionResult(本项目统一结果返回的类),特殊例外
(3)注意事项:
(a)action里面的方法如果存在有不需要加注解的方法,都应该改为私有方法
(b)若存在action的方法调用action里另一个方法,则确认2个方法是否都有url请求相对应,若都有,则把调用方法的代码改为return转发的url
(c)若action有局部变量,由于Struts2是多例,Spring是单例,所有局部变量都得加到方法里面获取
13、Json转换器更换:由于本项目原来的Json转换器是用Gson进行转换而不是Jackson来转换json,两者在转换json的时候有差异(比如boolean类型转换的时候一个有is前缀一个则没有),因此,本项目则写一个新的Gson转换器来替换Jackson转换器
(1)把spring-mvc.xml调整为:
(2)新建json转化器:GsonHttpMessageConverter
public class GsonHttpMessageConverter extends AbstractHttpMessageConverter
更换框架是一个很大的工作量,如果项目的代码量越大,要改的代码则会更多,本项目花了5天把除了Controller层的代码外的都换好了,然后再花费2天分配给2个人,根据我写的规则,来更改Controller层和jsp页面的代码(注意:一定要选比较认真严格的年轻小伙子,因为一不小心就会眼花改乱了,本人比较恐怖,完美主义者之一,相信世界上还有很多比我恐怖的coder,感谢大家阅读)