- 浏览: 4917 次
- 性别:
文章分类
- 全部博客 (12)
- 语言的分类 详实 自然 专业 (1)
- ajax JSON源于弱类型脚本语言,所以仍旧需要一些转译过程。像这样一个系统的目标,就是能够对跨越网络的领域对象进行序列化和反序列化.如果我们的域对象是用java编写,那么在传递给json序列化器之前,我们仍需要手动把它们转译成一般的散列表和数组。整个数据往返给JSON序列化器之前,我们仍需要手动把它们转译成一般的散列表和数组。 (1)
- 工作的2/1 (1)
- 开发人 java代码 (4)
- 软件级 cpu江海 (1)
- 自动补全 (0)
- 今天就ok (1)
- 详实的servlet规范 (0)
- 详实 高水平 山娃娃 (2)
- 获取表单 数据 实体类 (1)
- 被链接的组件 转发的组件 (1)
- 技术慧聪 (1)
最新评论
使用 Spring 更好地处理 Struts 动作三种整合 Struts 应用程序与 Spring 的方式
George Franciscus
2005 年 10 月 11 日发布
Comments 7
您肯定已经听说过控制反转 (IOC) 设计模式,因为很长一段时间以来一直在流传关于它的信息。如果您在任何功能中使用过 Spring 框架,那么您就知道其原理的作用。在本文中,我利用这一原理把一个 Struts 应用程序注入 Spring 框架,您将亲身体会到 IOC 模式的强大。
将一个 Struts 应用程序整合进 Spring 框架具有多方面的优点。首先,Spring 是为解决一些关于 JEE 的真实世界问题而设计的,比如复杂性、低性能和可测试性,等等。第二,Spring 框架包含一个 AOP 实现,允许您将面向方面技术应用于面向对象的代码。第三,一些人可能会说 Spring 框架只有 处理Struts 比 Struts 处理自己好。但是这是观点问题,我演示三种将 Struts 应用程序整合到 Spring 框架的方法后,具体由您自己决定使用哪一种。
我所演示的方法都是执行起来相对简单的,但是它们却具有明显不同的优点。我为每一种方法创建了一个独立而可用的例子,这样您就可以完全理解每种方法。 请参阅 下载部分获得完整例子源代码。请参阅 参考资料,下载 Struts MVC 和 Spring 框架。
为什么 Spring 这么了不起?
Spring 的创立者 Rod Johnson 以一种批判的眼光看待 Java™企业软件开发,并且提议很多企业难题都能够通过战略地使用 IOC 模式(也称作依赖注入)来解决。当 Rod 和一个具有奉献精神的开放源码开发者团队将这个理论应用于实践时,结果就产生了 Spring 框架。简言之,Spring 是一个轻型的容器,利用它可以使用一个外部 XML 配置文件方便地将对象连接在一起。每个对象都可以通过显示一个 JavaBean 属性收到一个到依赖对象的引用,留给您的简单任务就只是在一个 XML 配置文件中把它们连接好。
IOC 和 Spring
IOC 是一种使应用程序逻辑外在化的设计模式,所以它是被注入而不是被写入客户机代码中。将 IOC 与接口编程应用结合,就像 Spring 框架那样,产生了一种架构,这种架构能够减少客户机对特定实现逻辑的依赖。请参阅 参考资料了解更多关于 IOC 和 Spring 的信息。
依赖注入是一个强大的特性,但是 Spring 框架能够提供更多特性。Spring 支持可插拔的事务管理器,可以给您的事务处理提供更广泛的选择范围。它集成了领先的持久性框架,并且提供一个一致的异常层次结构。Spring 还提供了一种使用面向方面代码代替正常的面向对象代码的简单机制。
Spring AOP 允许您使用 拦截器在一个或多个执行点上拦截应用程序逻辑。加强应用程序在拦截器中的日志记录逻辑会产生一个更可读的、实用的代码基础,所以拦截器广泛用于日志记录。您很快就会看到,为了处理横切关注点,Spring AOP 发布了它自己的拦截器,您也可以编写您自己的拦截器。
整合 Struts 和 Spring
与 Struts 相似,Spring 可以作为一个 MVC 实现。这两种框架都具有自己的优点和缺点,尽管大部分人同意 Struts 在 MVC 方面仍然是最好的。很多开发团队已经学会在时间紧迫的时候利用 Struts 作为构造高品质软件的基础。Struts 具有如此大的推动力,以至于开发团队宁愿整合 Spring 框架的特性,而不愿意转换成 Spring MVC。没必要进行转换对您来说是一个好消息。Spring 架构允许您将 Struts 作为 Web 框架连接到基于 Spring 的业务和持久层。最后的结果就是现在一切条件都具备了。
在接下来的小窍门中,您将会了解到三种将 Struts MVC 整合到 Spring 框架的方法。我将揭示每种方法的缺陷并且对比它们的优点。 一旦您了解到所有三种方法的作用,我将会向您展示一个令人兴奋的应用程序,这个程序使用的是这三种方法中我最喜欢的一种。
三个小窍门
接下来的每种整合技术(或者窍门)都有自己的优点和特点。我偏爱其中的一种,但是我知道这三种都能够加深您对 Struts 和 Spring 的理解。在处理各种不同情况的时候,这将给您提供一个广阔的选择范围。方法如下:
使用 Spring 的 ActionSupport类整合 Structs
使用 Spring 的 DelegatingRequestProcessor覆盖 Struts 的 RequestProcessor
将 Struts Action管理委托给 Spring 框架
装载应用程序环境
无论您使用哪种技术,都需要使用 Spring 的 ContextLoaderPlugin为 Struts 的 ActionServlet装载 Spring 应用程序环境。就像添加任何其他插件一样,简单地向您的 struts-config.xml 文件添加该插件,如下所示:
<plug-in className=
"org.springframework.web.struts.ContextLoaderPlugIn">
<set-property property=
"contextConfigLocation" value="/WEB-INF/beans.xml"/>
</plug-in>
前面已经提到过,在 下载部分,您能够找到这三个完全可使用的例子的完整源代码。每个例子都为一个书籍搜索应用程序提供一种不同的 Struts 和 Spring 的整合方法。您可以在这里看到例子的要点,但是您也可以下载应用程序以查看所有的细节。
窍门 1. 使用 Spring 的 ActionSupport
手动创建一个 Spring 环境是一种整合 Struts 和 Spring 的最直观的方式。为了使它变得更简单,Spring 提供了一些帮助。为了方便地获得 Spring 环境,org.springframework.web.struts.ActionSupport类提供了一个 getWebApplicationContext()方法。您所做的只是从 Spring 的 ActionSupport而不是 Struts Action类扩展您的动作,如清单 1 所示:
清单 1. 使用 ActionSupport 整合 Struts
package ca.nexcel.books.actions;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.ActionError;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.DynaActionForm;
import org.springframework.context.ApplicationContext;
import org.springframework.web.struts.ActionSupport;
import ca.nexcel.books.beans.Book;
import ca.nexcel.books.business.BookService;
public class SearchSubmit extends ActionSupport { |(1)
public ActionForward execute(
ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException {
DynaActionForm searchForm = (DynaActionForm) form;
String isbn = (String) searchForm.get("isbn");
//the old fashion way
//BookService bookService = new BookServiceImpl();
ApplicationContext ctx =
getWebApplicationContext(); |(2)
BookService bookService =
(BookService) ctx.getBean("bookService"); |(3)
Book book = bookService.read(isbn.trim());
if (null == book) {
ActionErrors errors = new ActionErrors();
errors.add(ActionErrors.GLOBAL_ERROR,new ActionError
("message.notfound"));
saveErrors(request, errors);
return mapping.findForward("failure") ;
}
request.setAttribute("book", book);
return mapping.findForward("success");
}
}
让我们快速思考一下这里到底发生了什么。在 (1) 处,我通过从 Spring 的 ActionSupport类而不是 Struts 的 Action类进行扩展,创建了一个新的 Action。在 (2) 处,我使用 getWebApplicationContext()方法获得一个 ApplicationContext。为了获得业务服务,我使用在 (2) 处获得的环境在 (3) 处查找一个 Spring bean。
这种技术很简单并且易于理解。不幸的是,它将 Struts 动作与 Spring 框架耦合在一起。如果您想替换掉 Spring,那么您必须重写代码。并且,由于 Struts 动作不在 Spring 的控制之下,所以它不能获得 Spring AOP 的优势。当使用多重独立的 Spring 环境时,这种技术可能有用,但是在大多数情况下,这种方法不如另外两种方法合适。
窍门 2. 覆盖 RequestProcessor
将 Spring 从 Struts 动作中分离是一个更巧妙的设计选择。分离的一种方法是使用 org.springframework.web.struts.DelegatingRequestProcessor类来覆盖 Struts 的 RequestProcessor处理程序,如清单 2 所示:
清单 2. 通过 Spring 的 DelegatingRequestProcessor 进行整合
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE struts-config PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 1.1//EN"
"http://jakarta.apache.org/struts/dtds/struts-config_1_1.dtd">
<struts-config>
<form-beans>
<form-bean name="searchForm"
type="org.apache.struts.validator.DynaValidatorForm">
<form-property name="isbn" type="java.lang.String"/>
</form-bean>
</form-beans>
<global-forwards type="org.apache.struts.action.ActionForward">
<forward name="welcome" path="/welcome.do"/>
<forward name="searchEntry" path="/searchEntry.do"/>
<forward name="searchSubmit" path="/searchSubmit.do"/>
</global-forwards>
<action-mappings>
<action path="/welcome" forward="/WEB-INF/pages/welcome.htm"/>
<action path="/searchEntry" forward="/WEB-INF/pages/search.jsp"/>
<action path="/searchSubmit"
type="ca.nexcel.books.actions.SearchSubmit"
input="/searchEntry.do"
validate="true"
name="searchForm">
<forward name="success" path="/WEB-INF/pages/detail.jsp"/>
<forward name="failure" path="/WEB-INF/pages/search.jsp"/>
</action>
</action-mappings>
<message-resources parameter="ApplicationResources"/>
<controller processorClass="org.springframework.web.struts.
DelegatingRequestProcessor"/> |(1)
<plug-in className="org.apache.struts.validator.ValidatorPlugIn">
<set-property property="pathnames"
value="/WEB-INF/validator-rules.xml,/WEB-INF/validation.xml"/>
</plug-in>
<plug-in className="org.springframework.web.struts.ContextLoaderPlugIn">
<set-property property="csntextConfigLocation" value="/WEB-INF/beans.xml"/>
</plug-in>
</struts-config>
我利用了 <controller>标记来用 DelegatingRequestProcessor覆盖默认的 Struts RequestProcessor。下一步是在我的 Spring 配置文件中注册该动作,如清单 3 所示:
清单 3. 在 Spring 配置文件中注册一个动作
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean id="bookService" class="ca.nexcel.books.business.BookServiceImpl"/>
<bean name="/searchSubmit"
class="ca.nexcel.books.actions.SearchSubmit"> |(1)
<property name="bookService">
<ref bean="bookService"/>
</property>
</bean>
</beans>
注意:在 (1) 处,我使用名称属性注册了一个 bean,以匹配 struts-config 动作映射名称。SearchSubmit动作揭示了一个 JavaBean 属性,允许 Spring 在运行时填充属性,如清单 4 所示:
清单 4. 具有 JavaBean 属性的 Struts 动作
package ca.nexcel.books.actions;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionError;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.DynaActionForm;
import ca.nexcel.books.beans.Book;
import ca.nexcel.books.business.BookService;
public class SearchSubmit extends Action {
private BookService bookService;
public BookService getBookService() {
return bookService;
}
public void setBookService(BookService bookService) { | (1)
this.bookService = bookService;
}
public ActionForward execute(
ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException {
DynaActionForm searchForm = (DynaActionForm) form;
String isbn = (String) searchForm.get("isbn");
Book book = getBookService().read(isbn.trim()); |(2)
if (null == book) {
ActionErrors errors = new ActionErrors();
errors.add(ActionErrors.GLOBAL_ERROR,new ActionError("message.notfound"));
saveErrors(request, errors);
return mapping.findForward("failure") ;
}
request.setAttribute("book", book);
return mapping.findForward("success");
}
}
在清单 4 中,您可以了解到如何创建 Struts 动作。在 (1) 处,我创建了一个 JavaBean 属性。DelegatingRequestProcessor自动地配置这种属性。这种设计使 Struts 动作并不知道它正被 Spring 管理,并且使您能够利用 Sping 的动作管理框架的所有优点。由于您的 Struts 动作注意不到 Spring 的存在,所以您不需要重写您的 Struts 代码就可以使用其他控制反转容器来替换掉 Spring。
DelegatingRequestProcessor方法的确比第一种方法好,但是仍然存在一些问题。如果您使用一个不同的 RequestProcessor,则需要手动整合 Spring 的 DelegatingRequestProcessor。添加的代码会造成维护的麻烦并且将来会降低您的应用程序的灵活性。此外,还有过一些使用一系列命令来代替 Struts RequestProcessor的传闻。 这种改变将会对这种解决方法的使用寿命造成负面的影响。
窍门 3. 将动作管理委托给 Spring
一个更好的解决方法是将 Strut 动作管理委托给 Spring。您可以通过在 struts-config动作映射中注册一个代理来实现。代理负责在 Spring 环境中查找 Struts 动作。由于动作在 Spring 的控制之下,所以它可以填充动作的 JavaBean 属性,并为应用诸如 Spring 的 AOP 拦截器之类的特性带来了可能。
清单 5 中的 Action类与清单 4 中的相同。但是 struts-config 有一些不同:
清单 5. Spring 整合的委托方法
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE struts-config PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 1.1//EN"
"http://jakarta.apache.org/struts/dtds/struts-config_1_1.dtd">
<struts-config>
<form-beans>
<form-bean name="searchForm"
type="org.apache.struts.validator.DynaValidatorForm">
<form-property name="isbn" type="java.lang.String"/>
</form-bean>
</form-beans>
<global-forwards type="org.apache.struts.action.ActionForward">
<forward name="welcome" path="/welcome.do"/>
<forward name="searchEntry" path="/searchEntry.do"/>
<forward name="searchSubmit" path="/searchSubmit.do"/>
</global-forwards>
<action-mappings>
<action path="/welcome" forward="/WEB-INF/pages/welcome.htm"/>
<action path="/searchEntry" forward="/WEB-INF/pages/search.jsp"/>
<action path="/searchSubmit"
type="org.springframework.web.struts.DelegatingActionProxy" |(1)
input="/searchEntry.do"
validate="true"
name="searchForm">
<forward name="success" path="/WEB-INF/pages/detail.jsp"/>
<forward name="failure" path="/WEB-INF/pages/search.jsp"/>
</action>
</action-mappings>
<message-resources parameter="ApplicationResources"/>
<plug-in className="org.apache.struts.validator.ValidatorPlugIn">
<set-property
property="pathnames"
value="/WEB-INF/validator-rules.xml,/WEB-INF/validation.xml"/>
</plug-in>
<plug-in
className="org.springframework.web.struts.ContextLoaderPlugIn">
<set-property property="contextConfigLocation" value="/WEB-INF/beans.xml"/>
</plug-in>
</struts-config>
清单 5 是一个典型的 struts-config.xml 文件,只有一个小小的差别。它注册 Spring 代理类的名称,而不是声明动作的类名,如(1)处所示。DelegatingActionProxy 类使用动作映射名称查找 Spring 环境中的动作。这就是我们使用 ContextLoaderPlugIn声明的环境。
将一个 Struts 动作注册为一个 Spring bean 是非常直观的,如清单 6 所示。我利用动作映射使用 <bean>标记的名称属性(在这个例子中是 "/searchSubmit")简单地创建了一个 bean。这个动作的 JavaBean 属性像任何 Spring bean 一样被填充:
清单 6. 在 Spring 环境中注册一个 Struts 动作
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean id="bookService" class="ca.nexcel.books.business.BookServiceImpl"/>
<bean name="/searchSubmit"
class="ca.nexcel.books.actions.SearchSubmit">
<property name="bookService">
<ref bean="bookService"/>
</property>
</bean>
</beans>
动作委托的优点
动作委托解决方法是这三种方法中最好的。Struts 动作不了解 Spring,不对代码作任何改变就可用于非 Spring 应用程序中。RequestProcessor的改变不会影响它,并且它可以利用 Spring AOP 特性的优点。
动作委托的优点不止如此。一旦让 Spring 控制您的 Struts 动作,您就可以使用 Spring 给动作补充更强的活力。例如,没有 Spring 的话,所有的 Struts 动作都必须是线程安全的。如果您设置 <bean>标记的 singleton 属性为“false”,那么不管用何种方法,您的应用程序都将在每一个请求上有一个新生成的动作对象。您可能不需要这种特性,但是把它放在您的工具箱中也很好。您也可以利用 Spring 的生命周期方法。例如,当实例化 Struts 动作时,<bean>标记的 init-method 属性被用于运行一个方法。类似地,在从容器中删除 bean 之前,destroy-method 属性执行一个方法。这些方法是管理昂贵对象的好办法,它们以一种与 Servlet 生命周期相同的方式进行管理。
拦截 Struts
前面提到过,通过将 Struts 动作委托给 Spring 框架而整合 Struts 和 Spring 的一个主要的优点是:您可以将 Spring 的 AOP 拦截器应用于您的 Struts 动作。通过将 Spring 拦截器应用于 Struts 动作,您可以用最小的代价处理横切关注点。
虽然 Spring 提供很多内置拦截器,但是我将向您展示如何创建自己的拦截器并把它应用于一个 Struts 动作。为了使用拦截器,您需要做三件事:
创建拦截器。
注册拦截器。
声明在何处拦截代码。
这看起来非常简单的几句话却非常强大。例如,在清单 7 中,我为 Struts 动作创建了一个日志记录拦截器。 这个拦截器在每个方法调用之前打印一句话:
清单 7. 一个简单的日志记录拦截器
package ca.nexcel.books.interceptors;
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;
public class LoggingInterceptor implements MethodBeforeAdvice {
public void before(Method method, Object[] objects, Object o) throws Throwable {
System.out.println("logging before!");
}
}
这个拦截器非常简单。before()方法在拦截点中每个方法之前运行。在本例中,它打印出一句话,其实它可以做您想做的任何事。下一步就是在 Spring 配置文件中注册这个拦截器,如清单 8 所示:
清单 8. 在 Spring 配置文件中注册拦截器
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean id="bookService" class="ca.nexcel.books.business.BookServiceImpl"/>
<bean name="/searchSubmit"
class="ca.nexcel.books.actions.SearchSubmit">
<property name="bookService">
<ref bean="bookService"/>
</property>
</bean>
<!-- Interceptors -->
<bean name="logger"
class="ca.nexcel.books.interceptors.LoggingInterceptor"/> |(1)
<!-- AutoProxies -->
<bean name="loggingAutoProxy"
class="org.springframework.aop.framework.autoproxy.
BeanNameAutoProxyCreator"> |(2)
<property name="beanNames">
<value>/searchSubmit</valuesgt; |(3)
</property>
<property name="interceptorNames">
<list>
<value>logger</value> |(4)
</list>
</property>
</bean>
</beans>
您可能已经注意到了,清单 8 扩展了 清单 6中所示的应用程序以包含一个拦截器。具体细节如下:
在 (1) 处,我注册了这个拦截器。
在 (2) 处,我创建了一个 bean 名称自动代理,它描述如何应用拦截器。还有其他的方法定义拦截点,但是这种方法常见而简便。
在 (3) 处,我将 Struts 动作注册为将被拦截的 bean。如果您想要拦截其他的 Struts 动作,则只需要在 "beanNames" 下面创建附加的 <value>标记。
在 (4) 处,当拦截发生时,我执行了在 (1) 处创建的拦截器 bean 的名称。这里列出的所有拦截器都应用于“beanNames”。
就是这样。就像这个例子所展示的,将您的 Struts 动作置于 Spring 框架的控制之下,为处理您的 Struts 应用程序提供了一系列全新的选择。在本例中,使用动作委托可以轻松地利用 Spring 拦截器提高 Struts 应用程序中的日志记录能力。
结束语
在本文中,您已经学习了将 Struts 动作整合到 Spring 框架中的三种窍门。使用 Spring 的 ActionSupport来整合 Struts(第一种窍门中就是这样做的)简单而快捷,但是会将 Struts 动作与 Spring 框架耦合在一起。如果您需要将应用程序移植到一个不同的框架,则需要重写代码。第二种解决方法通过委托 RequestProcessor 巧妙地解开代码的耦合,但是它的可扩展性不强,并且当 Struts 的 RequestProcessor变成一系列命令时,这种方法就持续不了很长时间。第三种方法是这三种方法中最好的:将 Struts 动作委托给 Spring 框架可以使代码解耦,从而使您可以在您的 Struts 应用程序中利用 Spring 的特性(比如日志记录拦截器)。
三种 Struts-Spring 整合窍门中的每一种都被实现成一个完整可用的应用程序。请参阅 下载部分仔细研究它们。
下载资源
ActionSupport sample code (j-sr2-actionsupport.zip | 5 MB)
RequestProcessor sample code (j-sr2-requestprocessor.zip | 5 MB)
Delegate sample code (j-sr2-delegate.zip | 5 MB)
George Franciscus
2005 年 10 月 11 日发布
Comments 7
您肯定已经听说过控制反转 (IOC) 设计模式,因为很长一段时间以来一直在流传关于它的信息。如果您在任何功能中使用过 Spring 框架,那么您就知道其原理的作用。在本文中,我利用这一原理把一个 Struts 应用程序注入 Spring 框架,您将亲身体会到 IOC 模式的强大。
将一个 Struts 应用程序整合进 Spring 框架具有多方面的优点。首先,Spring 是为解决一些关于 JEE 的真实世界问题而设计的,比如复杂性、低性能和可测试性,等等。第二,Spring 框架包含一个 AOP 实现,允许您将面向方面技术应用于面向对象的代码。第三,一些人可能会说 Spring 框架只有 处理Struts 比 Struts 处理自己好。但是这是观点问题,我演示三种将 Struts 应用程序整合到 Spring 框架的方法后,具体由您自己决定使用哪一种。
我所演示的方法都是执行起来相对简单的,但是它们却具有明显不同的优点。我为每一种方法创建了一个独立而可用的例子,这样您就可以完全理解每种方法。 请参阅 下载部分获得完整例子源代码。请参阅 参考资料,下载 Struts MVC 和 Spring 框架。
为什么 Spring 这么了不起?
Spring 的创立者 Rod Johnson 以一种批判的眼光看待 Java™企业软件开发,并且提议很多企业难题都能够通过战略地使用 IOC 模式(也称作依赖注入)来解决。当 Rod 和一个具有奉献精神的开放源码开发者团队将这个理论应用于实践时,结果就产生了 Spring 框架。简言之,Spring 是一个轻型的容器,利用它可以使用一个外部 XML 配置文件方便地将对象连接在一起。每个对象都可以通过显示一个 JavaBean 属性收到一个到依赖对象的引用,留给您的简单任务就只是在一个 XML 配置文件中把它们连接好。
IOC 和 Spring
IOC 是一种使应用程序逻辑外在化的设计模式,所以它是被注入而不是被写入客户机代码中。将 IOC 与接口编程应用结合,就像 Spring 框架那样,产生了一种架构,这种架构能够减少客户机对特定实现逻辑的依赖。请参阅 参考资料了解更多关于 IOC 和 Spring 的信息。
依赖注入是一个强大的特性,但是 Spring 框架能够提供更多特性。Spring 支持可插拔的事务管理器,可以给您的事务处理提供更广泛的选择范围。它集成了领先的持久性框架,并且提供一个一致的异常层次结构。Spring 还提供了一种使用面向方面代码代替正常的面向对象代码的简单机制。
Spring AOP 允许您使用 拦截器在一个或多个执行点上拦截应用程序逻辑。加强应用程序在拦截器中的日志记录逻辑会产生一个更可读的、实用的代码基础,所以拦截器广泛用于日志记录。您很快就会看到,为了处理横切关注点,Spring AOP 发布了它自己的拦截器,您也可以编写您自己的拦截器。
整合 Struts 和 Spring
与 Struts 相似,Spring 可以作为一个 MVC 实现。这两种框架都具有自己的优点和缺点,尽管大部分人同意 Struts 在 MVC 方面仍然是最好的。很多开发团队已经学会在时间紧迫的时候利用 Struts 作为构造高品质软件的基础。Struts 具有如此大的推动力,以至于开发团队宁愿整合 Spring 框架的特性,而不愿意转换成 Spring MVC。没必要进行转换对您来说是一个好消息。Spring 架构允许您将 Struts 作为 Web 框架连接到基于 Spring 的业务和持久层。最后的结果就是现在一切条件都具备了。
在接下来的小窍门中,您将会了解到三种将 Struts MVC 整合到 Spring 框架的方法。我将揭示每种方法的缺陷并且对比它们的优点。 一旦您了解到所有三种方法的作用,我将会向您展示一个令人兴奋的应用程序,这个程序使用的是这三种方法中我最喜欢的一种。
三个小窍门
接下来的每种整合技术(或者窍门)都有自己的优点和特点。我偏爱其中的一种,但是我知道这三种都能够加深您对 Struts 和 Spring 的理解。在处理各种不同情况的时候,这将给您提供一个广阔的选择范围。方法如下:
使用 Spring 的 ActionSupport类整合 Structs
使用 Spring 的 DelegatingRequestProcessor覆盖 Struts 的 RequestProcessor
将 Struts Action管理委托给 Spring 框架
装载应用程序环境
无论您使用哪种技术,都需要使用 Spring 的 ContextLoaderPlugin为 Struts 的 ActionServlet装载 Spring 应用程序环境。就像添加任何其他插件一样,简单地向您的 struts-config.xml 文件添加该插件,如下所示:
<plug-in className=
"org.springframework.web.struts.ContextLoaderPlugIn">
<set-property property=
"contextConfigLocation" value="/WEB-INF/beans.xml"/>
</plug-in>
前面已经提到过,在 下载部分,您能够找到这三个完全可使用的例子的完整源代码。每个例子都为一个书籍搜索应用程序提供一种不同的 Struts 和 Spring 的整合方法。您可以在这里看到例子的要点,但是您也可以下载应用程序以查看所有的细节。
窍门 1. 使用 Spring 的 ActionSupport
手动创建一个 Spring 环境是一种整合 Struts 和 Spring 的最直观的方式。为了使它变得更简单,Spring 提供了一些帮助。为了方便地获得 Spring 环境,org.springframework.web.struts.ActionSupport类提供了一个 getWebApplicationContext()方法。您所做的只是从 Spring 的 ActionSupport而不是 Struts Action类扩展您的动作,如清单 1 所示:
清单 1. 使用 ActionSupport 整合 Struts
package ca.nexcel.books.actions;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.ActionError;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.DynaActionForm;
import org.springframework.context.ApplicationContext;
import org.springframework.web.struts.ActionSupport;
import ca.nexcel.books.beans.Book;
import ca.nexcel.books.business.BookService;
public class SearchSubmit extends ActionSupport { |(1)
public ActionForward execute(
ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException {
DynaActionForm searchForm = (DynaActionForm) form;
String isbn = (String) searchForm.get("isbn");
//the old fashion way
//BookService bookService = new BookServiceImpl();
ApplicationContext ctx =
getWebApplicationContext(); |(2)
BookService bookService =
(BookService) ctx.getBean("bookService"); |(3)
Book book = bookService.read(isbn.trim());
if (null == book) {
ActionErrors errors = new ActionErrors();
errors.add(ActionErrors.GLOBAL_ERROR,new ActionError
("message.notfound"));
saveErrors(request, errors);
return mapping.findForward("failure") ;
}
request.setAttribute("book", book);
return mapping.findForward("success");
}
}
让我们快速思考一下这里到底发生了什么。在 (1) 处,我通过从 Spring 的 ActionSupport类而不是 Struts 的 Action类进行扩展,创建了一个新的 Action。在 (2) 处,我使用 getWebApplicationContext()方法获得一个 ApplicationContext。为了获得业务服务,我使用在 (2) 处获得的环境在 (3) 处查找一个 Spring bean。
这种技术很简单并且易于理解。不幸的是,它将 Struts 动作与 Spring 框架耦合在一起。如果您想替换掉 Spring,那么您必须重写代码。并且,由于 Struts 动作不在 Spring 的控制之下,所以它不能获得 Spring AOP 的优势。当使用多重独立的 Spring 环境时,这种技术可能有用,但是在大多数情况下,这种方法不如另外两种方法合适。
窍门 2. 覆盖 RequestProcessor
将 Spring 从 Struts 动作中分离是一个更巧妙的设计选择。分离的一种方法是使用 org.springframework.web.struts.DelegatingRequestProcessor类来覆盖 Struts 的 RequestProcessor处理程序,如清单 2 所示:
清单 2. 通过 Spring 的 DelegatingRequestProcessor 进行整合
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE struts-config PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 1.1//EN"
"http://jakarta.apache.org/struts/dtds/struts-config_1_1.dtd">
<struts-config>
<form-beans>
<form-bean name="searchForm"
type="org.apache.struts.validator.DynaValidatorForm">
<form-property name="isbn" type="java.lang.String"/>
</form-bean>
</form-beans>
<global-forwards type="org.apache.struts.action.ActionForward">
<forward name="welcome" path="/welcome.do"/>
<forward name="searchEntry" path="/searchEntry.do"/>
<forward name="searchSubmit" path="/searchSubmit.do"/>
</global-forwards>
<action-mappings>
<action path="/welcome" forward="/WEB-INF/pages/welcome.htm"/>
<action path="/searchEntry" forward="/WEB-INF/pages/search.jsp"/>
<action path="/searchSubmit"
type="ca.nexcel.books.actions.SearchSubmit"
input="/searchEntry.do"
validate="true"
name="searchForm">
<forward name="success" path="/WEB-INF/pages/detail.jsp"/>
<forward name="failure" path="/WEB-INF/pages/search.jsp"/>
</action>
</action-mappings>
<message-resources parameter="ApplicationResources"/>
<controller processorClass="org.springframework.web.struts.
DelegatingRequestProcessor"/> |(1)
<plug-in className="org.apache.struts.validator.ValidatorPlugIn">
<set-property property="pathnames"
value="/WEB-INF/validator-rules.xml,/WEB-INF/validation.xml"/>
</plug-in>
<plug-in className="org.springframework.web.struts.ContextLoaderPlugIn">
<set-property property="csntextConfigLocation" value="/WEB-INF/beans.xml"/>
</plug-in>
</struts-config>
我利用了 <controller>标记来用 DelegatingRequestProcessor覆盖默认的 Struts RequestProcessor。下一步是在我的 Spring 配置文件中注册该动作,如清单 3 所示:
清单 3. 在 Spring 配置文件中注册一个动作
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean id="bookService" class="ca.nexcel.books.business.BookServiceImpl"/>
<bean name="/searchSubmit"
class="ca.nexcel.books.actions.SearchSubmit"> |(1)
<property name="bookService">
<ref bean="bookService"/>
</property>
</bean>
</beans>
注意:在 (1) 处,我使用名称属性注册了一个 bean,以匹配 struts-config 动作映射名称。SearchSubmit动作揭示了一个 JavaBean 属性,允许 Spring 在运行时填充属性,如清单 4 所示:
清单 4. 具有 JavaBean 属性的 Struts 动作
package ca.nexcel.books.actions;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionError;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.DynaActionForm;
import ca.nexcel.books.beans.Book;
import ca.nexcel.books.business.BookService;
public class SearchSubmit extends Action {
private BookService bookService;
public BookService getBookService() {
return bookService;
}
public void setBookService(BookService bookService) { | (1)
this.bookService = bookService;
}
public ActionForward execute(
ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException {
DynaActionForm searchForm = (DynaActionForm) form;
String isbn = (String) searchForm.get("isbn");
Book book = getBookService().read(isbn.trim()); |(2)
if (null == book) {
ActionErrors errors = new ActionErrors();
errors.add(ActionErrors.GLOBAL_ERROR,new ActionError("message.notfound"));
saveErrors(request, errors);
return mapping.findForward("failure") ;
}
request.setAttribute("book", book);
return mapping.findForward("success");
}
}
在清单 4 中,您可以了解到如何创建 Struts 动作。在 (1) 处,我创建了一个 JavaBean 属性。DelegatingRequestProcessor自动地配置这种属性。这种设计使 Struts 动作并不知道它正被 Spring 管理,并且使您能够利用 Sping 的动作管理框架的所有优点。由于您的 Struts 动作注意不到 Spring 的存在,所以您不需要重写您的 Struts 代码就可以使用其他控制反转容器来替换掉 Spring。
DelegatingRequestProcessor方法的确比第一种方法好,但是仍然存在一些问题。如果您使用一个不同的 RequestProcessor,则需要手动整合 Spring 的 DelegatingRequestProcessor。添加的代码会造成维护的麻烦并且将来会降低您的应用程序的灵活性。此外,还有过一些使用一系列命令来代替 Struts RequestProcessor的传闻。 这种改变将会对这种解决方法的使用寿命造成负面的影响。
窍门 3. 将动作管理委托给 Spring
一个更好的解决方法是将 Strut 动作管理委托给 Spring。您可以通过在 struts-config动作映射中注册一个代理来实现。代理负责在 Spring 环境中查找 Struts 动作。由于动作在 Spring 的控制之下,所以它可以填充动作的 JavaBean 属性,并为应用诸如 Spring 的 AOP 拦截器之类的特性带来了可能。
清单 5 中的 Action类与清单 4 中的相同。但是 struts-config 有一些不同:
清单 5. Spring 整合的委托方法
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE struts-config PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 1.1//EN"
"http://jakarta.apache.org/struts/dtds/struts-config_1_1.dtd">
<struts-config>
<form-beans>
<form-bean name="searchForm"
type="org.apache.struts.validator.DynaValidatorForm">
<form-property name="isbn" type="java.lang.String"/>
</form-bean>
</form-beans>
<global-forwards type="org.apache.struts.action.ActionForward">
<forward name="welcome" path="/welcome.do"/>
<forward name="searchEntry" path="/searchEntry.do"/>
<forward name="searchSubmit" path="/searchSubmit.do"/>
</global-forwards>
<action-mappings>
<action path="/welcome" forward="/WEB-INF/pages/welcome.htm"/>
<action path="/searchEntry" forward="/WEB-INF/pages/search.jsp"/>
<action path="/searchSubmit"
type="org.springframework.web.struts.DelegatingActionProxy" |(1)
input="/searchEntry.do"
validate="true"
name="searchForm">
<forward name="success" path="/WEB-INF/pages/detail.jsp"/>
<forward name="failure" path="/WEB-INF/pages/search.jsp"/>
</action>
</action-mappings>
<message-resources parameter="ApplicationResources"/>
<plug-in className="org.apache.struts.validator.ValidatorPlugIn">
<set-property
property="pathnames"
value="/WEB-INF/validator-rules.xml,/WEB-INF/validation.xml"/>
</plug-in>
<plug-in
className="org.springframework.web.struts.ContextLoaderPlugIn">
<set-property property="contextConfigLocation" value="/WEB-INF/beans.xml"/>
</plug-in>
</struts-config>
清单 5 是一个典型的 struts-config.xml 文件,只有一个小小的差别。它注册 Spring 代理类的名称,而不是声明动作的类名,如(1)处所示。DelegatingActionProxy 类使用动作映射名称查找 Spring 环境中的动作。这就是我们使用 ContextLoaderPlugIn声明的环境。
将一个 Struts 动作注册为一个 Spring bean 是非常直观的,如清单 6 所示。我利用动作映射使用 <bean>标记的名称属性(在这个例子中是 "/searchSubmit")简单地创建了一个 bean。这个动作的 JavaBean 属性像任何 Spring bean 一样被填充:
清单 6. 在 Spring 环境中注册一个 Struts 动作
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean id="bookService" class="ca.nexcel.books.business.BookServiceImpl"/>
<bean name="/searchSubmit"
class="ca.nexcel.books.actions.SearchSubmit">
<property name="bookService">
<ref bean="bookService"/>
</property>
</bean>
</beans>
动作委托的优点
动作委托解决方法是这三种方法中最好的。Struts 动作不了解 Spring,不对代码作任何改变就可用于非 Spring 应用程序中。RequestProcessor的改变不会影响它,并且它可以利用 Spring AOP 特性的优点。
动作委托的优点不止如此。一旦让 Spring 控制您的 Struts 动作,您就可以使用 Spring 给动作补充更强的活力。例如,没有 Spring 的话,所有的 Struts 动作都必须是线程安全的。如果您设置 <bean>标记的 singleton 属性为“false”,那么不管用何种方法,您的应用程序都将在每一个请求上有一个新生成的动作对象。您可能不需要这种特性,但是把它放在您的工具箱中也很好。您也可以利用 Spring 的生命周期方法。例如,当实例化 Struts 动作时,<bean>标记的 init-method 属性被用于运行一个方法。类似地,在从容器中删除 bean 之前,destroy-method 属性执行一个方法。这些方法是管理昂贵对象的好办法,它们以一种与 Servlet 生命周期相同的方式进行管理。
拦截 Struts
前面提到过,通过将 Struts 动作委托给 Spring 框架而整合 Struts 和 Spring 的一个主要的优点是:您可以将 Spring 的 AOP 拦截器应用于您的 Struts 动作。通过将 Spring 拦截器应用于 Struts 动作,您可以用最小的代价处理横切关注点。
虽然 Spring 提供很多内置拦截器,但是我将向您展示如何创建自己的拦截器并把它应用于一个 Struts 动作。为了使用拦截器,您需要做三件事:
创建拦截器。
注册拦截器。
声明在何处拦截代码。
这看起来非常简单的几句话却非常强大。例如,在清单 7 中,我为 Struts 动作创建了一个日志记录拦截器。 这个拦截器在每个方法调用之前打印一句话:
清单 7. 一个简单的日志记录拦截器
package ca.nexcel.books.interceptors;
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;
public class LoggingInterceptor implements MethodBeforeAdvice {
public void before(Method method, Object[] objects, Object o) throws Throwable {
System.out.println("logging before!");
}
}
这个拦截器非常简单。before()方法在拦截点中每个方法之前运行。在本例中,它打印出一句话,其实它可以做您想做的任何事。下一步就是在 Spring 配置文件中注册这个拦截器,如清单 8 所示:
清单 8. 在 Spring 配置文件中注册拦截器
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean id="bookService" class="ca.nexcel.books.business.BookServiceImpl"/>
<bean name="/searchSubmit"
class="ca.nexcel.books.actions.SearchSubmit">
<property name="bookService">
<ref bean="bookService"/>
</property>
</bean>
<!-- Interceptors -->
<bean name="logger"
class="ca.nexcel.books.interceptors.LoggingInterceptor"/> |(1)
<!-- AutoProxies -->
<bean name="loggingAutoProxy"
class="org.springframework.aop.framework.autoproxy.
BeanNameAutoProxyCreator"> |(2)
<property name="beanNames">
<value>/searchSubmit</valuesgt; |(3)
</property>
<property name="interceptorNames">
<list>
<value>logger</value> |(4)
</list>
</property>
</bean>
</beans>
您可能已经注意到了,清单 8 扩展了 清单 6中所示的应用程序以包含一个拦截器。具体细节如下:
在 (1) 处,我注册了这个拦截器。
在 (2) 处,我创建了一个 bean 名称自动代理,它描述如何应用拦截器。还有其他的方法定义拦截点,但是这种方法常见而简便。
在 (3) 处,我将 Struts 动作注册为将被拦截的 bean。如果您想要拦截其他的 Struts 动作,则只需要在 "beanNames" 下面创建附加的 <value>标记。
在 (4) 处,当拦截发生时,我执行了在 (1) 处创建的拦截器 bean 的名称。这里列出的所有拦截器都应用于“beanNames”。
就是这样。就像这个例子所展示的,将您的 Struts 动作置于 Spring 框架的控制之下,为处理您的 Struts 应用程序提供了一系列全新的选择。在本例中,使用动作委托可以轻松地利用 Spring 拦截器提高 Struts 应用程序中的日志记录能力。
结束语
在本文中,您已经学习了将 Struts 动作整合到 Spring 框架中的三种窍门。使用 Spring 的 ActionSupport来整合 Struts(第一种窍门中就是这样做的)简单而快捷,但是会将 Struts 动作与 Spring 框架耦合在一起。如果您需要将应用程序移植到一个不同的框架,则需要重写代码。第二种解决方法通过委托 RequestProcessor 巧妙地解开代码的耦合,但是它的可扩展性不强,并且当 Struts 的 RequestProcessor变成一系列命令时,这种方法就持续不了很长时间。第三种方法是这三种方法中最好的:将 Struts 动作委托给 Spring 框架可以使代码解耦,从而使您可以在您的 Struts 应用程序中利用 Spring 的特性(比如日志记录拦截器)。
三种 Struts-Spring 整合窍门中的每一种都被实现成一个完整可用的应用程序。请参阅 下载部分仔细研究它们。
下载资源
ActionSupport sample code (j-sr2-actionsupport.zip | 5 MB)
RequestProcessor sample code (j-sr2-requestprocessor.zip | 5 MB)
Delegate sample code (j-sr2-delegate.zip | 5 MB)
相关推荐
Python课程设计,含有代码注释,新手也可看懂。毕业设计、期末大作业、课程设计、高分必看,下载下来,简单部署,就可以使用。 包含:项目源码、数据库脚本、软件工具等,该项目可以作为毕设、课程设计使用,前后端代码都在里面。 该系统功能完善、界面美观、操作简单、功能齐全、管理便捷,具有很高的实际应用价值。
Python课程设计,含有代码注释,新手也可看懂。毕业设计、期末大作业、课程设计、高分必看,下载下来,简单部署,就可以使用。 包含:项目源码、数据库脚本、软件工具等,该项目可以作为毕设、课程设计使用,前后端代码都在里面。 该系统功能完善、界面美观、操作简单、功能齐全、管理便捷,具有很高的实际应用价值。
杂货产品检测43-YOLO(v5至v9)、CreateML、Paligemma、TFRecord、VOC数据集合集.rarIPCV分配-V6 2024-01-21 6:10 PM ============================= *与您的团队在计算机视觉项目上合作 *收集和组织图像 *了解和搜索非结构化图像数据 *注释,创建数据集 *导出,训练和部署计算机视觉模型 *使用主动学习随着时间的推移改善数据集 对于最先进的计算机视觉培训笔记本,您可以与此数据集一起使用 该数据集包括7012张图像。 家庭废物以createMl格式注释。 将以下预处理应用于每个图像: *像素数据的自动取向(带有Exif-Arientation剥离) *调整大小为640x640(拉伸) 没有应用图像增强技术。
Android 毕业设计,Android 毕业设计,小Android 程设计,含有代码注释,新手也可看懂。毕业设计、期末大作业、课程设计、高分必看,下载下来,简单部署,就可以使用。 包含:项目源码、数据库脚本、软件工具等,该项目可以作为毕设、课程设计使用,前后端代码都在里面。 该系统功能完善、界面美观、操作简单、功能齐全、管理便捷,具有很高的实际应用价值。
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、本项目仅用作交流学习参考,请切勿用于商业用途。
谁喜欢谁下载,没啥商业价值,comsol也能做,不过我这产量更大
Python课程设计,含有代码注释,新手也可看懂。毕业设计、期末大作业、课程设计、高分必看,下载下来,简单部署,就可以使用。 包含:项目源码、数据库脚本、软件工具等,该项目可以作为毕设、课程设计使用,前后端代码都在里面。 该系统功能完善、界面美观、操作简单、功能齐全、管理便捷,具有很高的实际应用价值。
Android 毕业设计,Android 毕业设计,小Android 程设计,含有代码注释,新手也可看懂。毕业设计、期末大作业、课程设计、高分必看,下载下来,简单部署,就可以使用。 包含:项目源码、数据库脚本、软件工具等,该项目可以作为毕设、课程设计使用,前后端代码都在里面。 该系统功能完善、界面美观、操作简单、功能齐全、管理便捷,具有很高的实际应用价值。
推箱子Python小游戏
该新媒体视域下的中国古诗词展演主要为管理员和用户两类用户角色提供需求,管理员在后台可以对系统进行全面管理,用户在前台可以进行查看系统信息,注册登录,查询校园失物,评论,下载校园失物等操作。 项目包含完整前后端源码和数据库文件 环境说明: 开发语言:Java 框架:ssm,mybatis JDK版本:JDK1.8 数据库:mysql 5.7 数据库工具:Navicat11 开发软件:eclipse/idea Maven包:Maven3.3 部署容器:tomcat7
内容概要:本文介绍了使用MATLAB实现PSO-BiLSTM-Attention粒子群优化双向长短期记忆神经网络融合注意力机制的多特征分类预测模型。通过PSO优化BiLSTM模型的超参数、引入注意力机制增强模型的特征提取能力,提升了多维度数据的分类精度。模型在金融风险预测、医疗健康预测、交通流量预测等多个领域具有广泛的应用前景。项目详细描述了模型架构、代码实现、训练与优化、模型评估与可视化、以及GUI界面设计等方面的内容。 适合人群:具备一定编程基础,工作1-3年的数据科学家和机器学习工程师。 使用场景及目标:① 金融、医疗、交通等领域的多特征分类预测任务;② 结合PSO优化BiLSTM超参数、引入注意力机制,提升模型预测准确度。 阅读建议:本文详细讲解了模型的理论背景、算法实现和应用案例,适合希望深入理解深度学习和优化算法的读者。建议结合代码和实际数据进行实验,以便更好地掌握模型的设计和优化过程。
Java项目-基于SSM的物资管理系统项目源码
Video_2024-12-18_000023.wmv
Python课程设计,含有代码注释,新手也可看懂。毕业设计、期末大作业、课程设计、高分必看,下载下来,简单部署,就可以使用。 包含:项目源码、数据库脚本、软件工具等,该项目可以作为毕设、课程设计使用,前后端代码都在里面。 该系统功能完善、界面美观、操作简单、功能齐全、管理便捷,具有很高的实际应用价值。
系统实现: 用户功能模块:用户点击进入到系统操作界面,可以对主页、个人中心、我的收藏管理、订单管理等功能模块,我的收藏管理:通过列表可以获取用户ID、收藏ID、表名、收藏名称、收藏图片信息并进行修改操作 管理员功能模块:管理员通过用户名和密码填写完成后进行登录。管理员登录成功后进入到系统操作界面,可以对主页、个人中心、用户管理、商品分类管理、商品信息管理、系统管理、订单管理等功能模块进行相对应操作。 项目包含完整前后端源码和数据库文件 环境说明: 开发语言:Java 框架:ssm,mybatis JDK版本:JDK1.8 数据库:mysql 5.7 数据库工具:Navicat11 开发软件:eclipse/idea Maven包:Maven3.3 服务器:tomcat7
1、嵌入式物联网单片机项目开发实战。例程经过精心编写,简单好用。 2、代码使用KEIL 标准库开发,当前在STM32F103运行,如果是STM32F103其他型号芯片,依然适用,请自行更改KEIL芯片型号以及FLASH容量即可。 3、软件下载时,请注意keil选择项是jlink还是stlink。 4、有偿指导v:wulianjishu666; 5、如果接入其他传感器,请查看发布的其他资料。 6、单片机与模块的接线,在代码当中均有定义,请自行对照。 7、若硬件差异,请根据自身情况调整代码,程序仅供参考学习。 8、代码有注释说明,请耐心阅读。
项目包含完整前后端源码和数据库文件 环境说明: 开发语言:Java 框架:ssm,mybatis JDK版本:JDK1.8 数据库:mysql 5.7 数据库工具:Navicat11 开发软件:eclipse/idea Maven包:Maven3.3 部署容器:tomcat7
Java项目-基于SSM的网上淘书吧
内容概要:本文详细介绍了 Oracle 19c 中的闪回技术,包括闪回查询、闪回事务查询、闪回丢弃、闪回表、闪回数据库和闪回归档。具体讲解了每种闪回技术的原理、配置方法、操作步骤和限制条件,并提供了具体的实例和 SQL 命令。目的是帮助数据库管理员和开发人员理解和掌握如何利用这些技术来提高数据恢复和错误修复的能力,减少数据库管理的复杂性和风险。 适合人群:Oracle 数据库管理员、数据库开发人员及维护人员。 使用场景及目标:① 使用闪回技术快速恢复因误操作或其他错误导致的数据丢失;② 配置闪回技术以实现高效的数据库恢复;③ 在日常运维中监控和管理闪回操作。 其他说明:本文不仅提供了理论上的解释,还包含了实际操作的示例,以便读者能够更好地理解和应用这些技术。