当前位置: 首页 > 工具软件 > jeeshop > 使用案例 >

结合开源电商jeeshop,修改项目前端框架为springmvc

燕刚捷
2023-12-01

 

首先,弄清楚springmvc跟struts使用的时候有哪些地方会有区别:

 

(一)从引入开始,struts2在web.xml中使用过滤器 (org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter)

而 springmvc采用 Servlet引入  org.springframework.web.servlet.DispatcherServlet

 

<!-- spring mvc servlet -->

<servlet>

<description>spring mvc servlet</description>

<servlet-name>springMvc</servlet-name>

<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

<init-param>

<description>spring mvc 配置文件</description>

<param-name>contextConfigLocation</param-name>

<param-value>classpath*:spring-mvc.xml</param-value>

</init-param>

<load-on-startup>1</load-on-startup>

</servlet>

<servlet-mapping>

<servlet-name>springMvc</servlet-name>

<url-pattern>*.action</url-pattern>

</servlet-mapping>

 

 

(二)请求过来之后的mapping,struts采用配置文件,action method等

这里的springmvc,最方便的写法还是 注解,比如

 

spring-mvc.xml

<!-- 自动扫描controller包下的所有类,使其认为spring mvc的控制器 -->

<context:component-scan base-package="net.jeeshop" />

 

<!-- 启动Spring MVC的注解功能,完成请求和注解POJO的映射 -->

<bean

class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">

<property name="messageConverters">

<list>

<ref bean="mappingJacksonHttpMessageConverter" />

</list>

</property>

</bean>

 

在普通的action上面加上

@Scope("prototype")   

@Controller("frontProductAction")   

@RequestMapping("/product")

 

(三)处理完请求,返回视图

struts配置在 result,然后对应到jsp页面,为了最小程度的改动代码,并且也是用jsp视图

 

 

 

<!-- 对模型视图名称的解析,即在模型视图名称添加前后缀 -->

<bean

class="org.springframework.web.servlet.view.InternalResourceViewResolver"

p:prefix="/" p:suffix=".jsp" />

 

然后action中对返回的String视图,定义成一个变量,然后将每个方法的返回String改为对应的变量名,去掉引号。

这一步可以使用 getPage.pl (专门从 struts的配置文件中转化出对应的 jsp路径,然后转变成springmvc的action中的上述赋值语句)

具体示例请参考下述步骤。

 

(四)最费时间的部分:

修改jsp页面里面的 struts标签,改为JSTL标签或者 springmvc标签。这里如果作者一开始使用JSTL标签的话,那么基本就不用修改了,

实际操作过程中,这一步耗费时间最多。。。 有点小的感悟就是,用标准化的东西还是有好处,在换其他的框架时不用改动,当然struts标签也有它的优势,

所以也是要综合考虑的。

 

 

详细步骤(已忽略配置文件部分):

【1】公共处理:

 

1.baseAction里面 实现的接口 ActionSuppoer,需要去掉,因为它是Struts的,为了保证代码最小改动,我寻找了 springmvc中获取 request response的方法,

(当然常规做法是在方法的参数里面直接写上request就可以使用了),模拟写了一个 springmcActionContext,继承SpringmvcContextHolder,实现了getRequest、

getResponse方法等等。  但实际上这个做法最后可以忽略了,因为找到了 springmvc的一个有用注解,可以在每个方法调用前执行一段代码【当然就可以在这一段

执行的时候,把参数request response 甚至 <T> e 注入到 BaseAction中,然后其他子类Action即可直接使用已赋值的变量了! 】

 

protected  Model model;

/*************

 *   获取request response

 */

protected HttpServletRequest request;

protected HttpServletResponse response;

 

@ModelAttribute

public void setReqAndRes(HttpServletRequest request,

HttpServletResponse response,@ModelAttribute("e") E e,String[] ids,Model model) {

this.e = e;  // 将request中的对象放入action,模拟struts2 属性对象的自动封装

this.request = request;

this.response = response;

this.model = model;

this.ids = ids;

model.addAttribute("e", e);

logger.error("BaseAction:method called before:request="+request+",response="+response

+",e="+JSON.toJSONString(e));

}

特别注意!这里的 model.addAttribute("e", e); 是把变量加入到 输出视图中,如果e的引用没有发生变化,则不需要重新加入一次,

如果 涉及到修改引用地址,则需要重新加入一次了!比如 e = 从数据库重新查出来的一个值,这时候,如果不重新加入,则返回视图获取不到!

 

 

2.BaseAction中 去掉 getRequest  getResponse方法等

因为子类action中 getRequest()要替换为 request ;getResponse()替换为 response。这两个对象都可直接取自 BaseAction属性。

 

 

3.BaseAction中 需要被子类继承了的方法 需要加上 requestmapping 注解,这样有些被子类重写的方法就不需要重复加 mapping路径了

 

 

 

【2】子模块处理部分

--------------------------------------   java action  部分------------------------------------- 

1. 先给action加上三个注解 

@Scope("prototype")   

@Controller   

@RequestMapping("/manage/user")          

 

@ModelAttribute

public void initStrutsActionParam(){

this.server = null ;  // null这个地方替换成当前action注入的service

}

 

找到struts的配置文件

 所有视图返回的地方,转换成 “视图赋值语句”,调用getPage.pl

 

 

 2.

  因为在baseaction中写好了直接获取requet response的方法【protected】

 替换所有的getRequest() 为 request

 替换所有的 getResponse() 为 response

 

 3.所有“需要”的方法加上 @requestMapping

 

4.找到spring的配置文件,配置action的地方,如果是注入的service bean,则在action中将其改为 autowired注解,并将setter getter删掉

  然后其他属性,就是非注入的,先注释掉,然后看哪些方法报错,将报错的方法中,选择public的方法[因为私有方法的变量不需要传到视图层]

  ① 先在方法声明中加上”Model model“ 然后方法体中加入 model.addAttribute(....); 这样表示将这个属性返回到视图[因为之前这些属性

  直接在action中定义,struts2就能够传递到视图层了]

  

5. 注意这个方法

@Override

protected void selectListAfter() {

pager.setPagerUrl(getBasePath() + "manage/?/selectList.action");

}

 

 

##### 6.拷贝这个方法: 这一步不需要了

public String selectList() throws Exception {

return super.selectList();

}

 

 

----------------------------- page页面部分:所有struts标签 替换成jstl或者spring 标签-------------------------------------

在 common.jsp中加入以下语句

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>

<c:set var="ctx" value="<%=request.getContextPath()%>"/>

<input type="hidden" id="namespace" value="${ctx}" /> 当然这里的namespace 跟 struts2的不一样,只是我这里取了一个名称而已。

 

 

5-0 a标签

<a href="${ctx}/manage/user/toAdd.action" method="toAdd" class="btn btn-success">

<i class="icon-plus-sign icon-white"></i> 添加

</a>

 

    button标签

<button method="${ctx}/manage/user/selectList.action" class="btn btn-primary" οnclick="selectList(this)">

<i class="icon-search icon-white"></i> 查询

</button>

 

 

<button method="${ctx}/manage/user/update.action"

class="btn btn-success">

<i class="icon-ok icon-white"></i> 保存

</button>

 

 

5-1         s:if  s:else 标签

<c:choose>

<c:when test="${role.id == ''}">

  

</c:when>

<c:otherwise>

 

</c:otherwise>

</c:choose>

 

<c:choose>

 <c:when test="${e.id=='' or e.id==null}">

  <input type="submit" value="新增" method="insert" οnclick="return onSubmit();" class="btn btn-primary" />

</c:when>

<c:otherwise>

 <input type="submit" value="保存" method="update" οnclick="return onSubmit();" class="btn btn-primary"/>

</c:otherwise>

            </c:choose>

 

【<input type="text" name="role_name" id="role_name" />        <input type="text" name="role_name" id="role_name" readonly="readonly"/>】

 

5-2      select标签

5-2-1 数据从数据库查询的

<select id="" name="">

    <c:forEach items="${roleList}" var="role">

<option value="${role.id}" <c:if test='${role.id == e.rid}'>selected='selected'</c:if> >${role.role_name}</option>

</c:forEach>

</select>

5-2-2 数据直接写死的

<select id="status" name="status" class="input-small">

<option value='0'></option>

<option value='1' <c:if test='${e.status=="y"}'>selected='selected'</c:if>>启用</option>

<option value='2' <c:if test='${e.status=="n"}'>selected='selected'</c:if>>禁用</option>

</select>

 

    5-3  列表循环

<c:forEach items="${pager.list}" var="user">  

 <tr>

  

 </tr>

</c:forEach>

 

 

<input type="hidden" name="id" label="id" value="${e.id}" />

 

============================================

未完成任务:

1.解决键值对 也有可能有其他的,需要唯一判断的地方,增加键 编辑的时候需要 唯一性验证。否则数据库报错

2.解决键值对编辑的时候,value字段不能够搜索的情况,mybatis bug

3.解决 系统设置功能模块,  并且保存完毕,之后不能继续保存的bug

4.解决定时调度的错误

Exception in thread "pool-2-thread-1" Exception in thread "pool-2-thread-3" java.lang.NullPointerException

at org.slf4j.impl.Log4jLoggerAdapter.error(Log4jLoggerAdapter.java:497)

at net.jeeshop.core.task.CancelOrderTask.run(CancelOrderTask.java:40)

at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)

at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)

at java.lang.Thread.run(Thread.java:662)

java.lang.NullPointerException

at org.slf4j.impl.Log4jLoggerAdapter.error(Log4jLoggerAdapter.java:497)

at net.jeeshop.core.task.ManageCacheTask.run(ManageCacheTask.java:36)

at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)

at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)

at java.lang.Thread.run(Thread.java:662)

Exception in thread "pool-2-thread-2" java.lang.NullPointerException

at org.slf4j.impl.Log4jLoggerAdapter.error(Log4jLoggerAdapter.java:497)

at net.jeeshop.core.task.SystemAutoNotifyTask.run(SystemAutoNotifyTask.java:47)

at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)

at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)

at java.lang.Thread.run(Thread.java:662)

2014-08-26 20:25:59 net.jeeshop.core.task.SystemAutoNotifyTask:47 ERROR - OrderCancelTask.run...

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

=================================================================================

经验:springmvc 加上 urlrewrite之后,/A/A.action 经常出问题,所以最好改为 /A/B.action

否则会下面这种错误:

No matching handler method found for servlet request: path '/product/product.action', method 'GET', parameters map[[empty]]

 

而不是这种错误:

No mapping found for HTTP request with URI [/jeeshop/product/product1.action] 【这种才是正常的错误】

 

 

=======================================================================================

jstl  判断list  是否为空,不能这样写 

 <c:when test="${requestScope.commentPager.list==null or 

 requestScope.commentPager.list.size == 0 }">

而应该这样写:

<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions"%>

 <c:if test="${fn:length(list) <= 0}">

        list对象为空

 </c:if>

 

======================================================================================

java.lang.ArithmeticException: / by zero 发生这种错误是因为一个数除以0的情况,0是不能作为被除数的

 

 

 

======================================================================================================

严重: Servlet.service() for servlet springMvc threw exception

org.springframework.validation.BindException: org.springframework.validation.BeanPropertyBindingResult: 1 errors

Field error in object 'e' on field 'catalogID': rejected value []; codes [typeMismatch.e.catalogID,typeMismatch.catalogID,typeMismatch.int,typeMismatch]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [e.catalogID,catalogID]; arguments []; default message [catalogID]]; default message [Failed to convert property value of type 'java.lang.String' to required type 'int' for property 'catalogID'; nested exception is java.lang.NumberFormatException: For input string: ""]

at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.doBind(HandlerMethodInvoker.java:810)

at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.resolveHandlerArguments(HandlerMethodInvoker.java:359)

at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.invokeHandlerMethod(HandlerMethodInvoker.java:153)

at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.invokeHandlerMethod(AnnotationMethodHandlerAdapter.java:426)

at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.handle(AnnotationMethodHandlerAdapter.java:414)

at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:790)

at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:719)

at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:644)

at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:560)

at javax.servlet.http.HttpServlet.service(HttpServlet.java:637)

at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)

at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)

at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)

at net.jeeshop.core.filter.EncodeFilter.doFilter(EncodeFilter.java:22) <=============  每次都在这里

at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)

at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)

..............................

 类似资料: