Combined with the open source e-commerce jeeshop, modify the front-end framework of the project to springmvc

 

First, figure out what is the difference between springmvc and struts:

 

(1) Since the introduction, struts2 uses filters in web.xml (org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter)

And springmvc uses Servlet to introduce 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 configuration file</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>

 

 

(2) Mapping after the request comes, struts uses configuration files, action methods, etc.

The most convenient way to write springmvc here is annotation, such as

 

spring-mvc.xml

<!-- Automatically scan all classes under the controller package to make it think that the controller of spring mvc -->

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

 

<!-- Start the annotation function of Spring MVC and complete the mapping of requests and annotation POJOs -->

<bean

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

<property name="messageConverters">

<list>

<ref bean="mappingJacksonHttpMessageConverter" />

</list>

</property>

</bean>

 

Add to the normal action

@Scope("prototype")   

@Controller("frontProductAction")   

@RequestMapping("/product")

 

(3) After processing the request, return to the view

struts is configured in the result, and then corresponds to the jsp page, in order to change the code to a minimum degree, and also use the jsp view

 

 

 

<!-- Parsing the name of the model view, that is, adding prefixes and suffixes to the name of the model view -->

<bean

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

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

 

Then in the action, the returned String view is defined as a variable, and then the returned String of each method is changed to the corresponding variable name, and the quotation marks are removed.

This step can use getPage.pl (specially convert the corresponding jsp path from the struts configuration file, and then convert it into the above assignment statement in the springmvc action)

For specific examples, please refer to the following steps.

 

(4) The most time-consuming part:

Modify the struts tag in the jsp page to JSTL tag or springmvc tag. Here, if the author uses JSTL tags at the beginning, there is basically no need to modify them.

In practice, this step takes the most time. . . A little insight is that it is still beneficial to use standardized things, and there is no need to change it when changing other frameworks. Of course, the struts tag also has its advantages.

So it has to be considered comprehensively.

 

 

Detailed steps (config file section ignored):

【1】Public processing:

 

1. The interface ActionSuppoer implemented in baseAction needs to be removed because it belongs to Struts. In order to ensure the minimum changes to the code, I searched for the method of obtaining the request response in springmvc.

(Of course, the conventional practice is to write request directly in the parameters of the method and it can be used), simulate and write a springmcActionContext, inherit SpringmvcContextHolder, and implement getRequest,

getResponse method and so on. But in fact, this practice can be ignored in the end, because a useful annotation of springmvc is found, and a piece of code can be executed before each method call [of course, it can be in this paragraph

When executing, inject the parameter request response or even <T> e into BaseAction, and then other subclass Actions can directly use the assigned variables!

 

protected  Model model;

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

 * Get 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; // Put the object in the request into the action to simulate the automatic encapsulation of the struts2 attribute object

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));

}

pay attention! The model.addAttribute("e", e); here is to add the variable to the output view. If the reference of e has not changed, it does not need to be added again.

If it involves modifying the reference address, you need to rejoin it again! For example, e = a value re-checked from the database. At this time, if you do not re-join, the returned view cannot be obtained!

 

 

2. Remove the getRequest getResponse method from BaseAction, etc.

Because getRequest() in subclass action is replaced by request; getResponse() is replaced by response. Both of these objects can be taken directly from the BaseAction property.

 

 

3. The methods in BaseAction that need to be inherited by subclasses need to be annotated with requestmapping, so that some methods overridden by subclasses do not need to repeat the mapping path.

 

 

 

[2] Submodule processing part

-------------------------------------- java action section --------- ---------------------------- 

1. First add three annotations to the action 

@Scope("prototype")   

@Controller   

@RequestMapping("/manage/user")          

 

@ModelAttribute

public void initStrutsActionParam(){

this.server = null ; // null is replaced by the service injected by the current action

}

 

Find the struts configuration file

 Where all views are returned, they are converted into "view assignment statements", and getPage.pl is called

 

 

 2.

  Because the method to directly obtain the requet response is written in the baseaction [protected]

 Replace all getRequest() with request

 Replace all getResponse() with response

 

 3. All "required" methods plus @requestMapping

 

4. Find the spring configuration file, configure the action place, if it is an injected service bean, change it to the autowired annotation in the action, and delete the setter getter

  Then other properties are non-injected. Comment out first, and then see which methods report errors. Among the methods that report errors, select the public method [because the variables of the private method do not need to be passed to the view layer]

  ① First add "Model model" to the method declaration and then add model.addAttribute(....) to the method body; this means that this attribute is returned to the view [because of the previous attributes

  Defined directly in action, struts2 can be passed to the view layer]

  

5. Pay attention to this method

@Override

protected void selectListAfter() {

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

}

 

 

##### 6. Copy this method: This step is not needed

public String selectList() throws Exception {

return super.selectList();

}

 

 

----------------------------- page page part: replace all struts tags with jstl or spring tags -------- -----------------------------

Add the following statement to 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}" /> Of course, the namespace here is different from that of struts2, but I just took a name here.

 

 

5-0 a label

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

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

</a>

 

    button label

<button method="${ctx}/manage/user/selectList.action" class="btn btn-primary" onclick="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 tag

<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" onclick="return onSubmit();" class="btn btn-primary" />

</c:when>

<c:otherwise>

 <input type="submit" value="保存" method="update" onclick="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 tag

5-2-1 Data queried from database

<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 Data is directly written to death

<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 List Loop

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

 <tr>

  

 </tr>

</c:forEach>

 

 

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

 

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

Unfinished tasks:

1. There may also be other key-value pairs that require unique judgment. When adding key editing, uniqueness verification is required. Otherwise, the database will report an error

2. Solve the problem that the value field cannot be searched when the key-value pair is edited, mybatis bug

3. Solve the bug that the system setting function module cannot be saved after saving it

4. Solve the error of timing scheduling

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...

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

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

Experience: After springmvc plus urlrewrite, /A/A.action often has problems, so it is best to change to /A/B.action

Otherwise, the following error will occur:

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

 

instead of this error:

No mapping found for HTTP request with URI [/jeeshop/product/product1.action] [This is a normal error]

 

 

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

jstl judges whether the list is empty, it cannot be written like this 

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

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

Instead it should be written like this:

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

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

        list object is empty

 </c:if>

 

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

java.lang.ArithmeticException: / by zero This error occurs because a number is divided by 0, and 0 cannot be used as a dividend

 

 

 

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

严重: 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) <============== here every time

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

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

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

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326433967&siteId=291194637