Spring开发指南读书笔记(一)

来源:互联网 发布:查找时间最短优先算法 编辑:程序博客网 时间:2024/06/09 16:27

Spring给程序员提供了一个轻量级的构建技术框架。它主要的特性就是控制反转IOC和面向切面AOP编程。

它的作用是使用基本的Bean来完成EJB可以完成的工作,提高了代码的可重用性,简单、松耦合和可测试性。

一个简单的Spring例子:

public interface Action {

 public String execute(String str);
}

实现类:

public class LowerAction implements Action{

 private String message;

 public String getMessage() {
  return message;
 }

 public void setMessage(String message) {
  this.message = message;
 }

 public String execute(String str) {
  return (getMessage()+str).toLowerCase();
 }
}

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="TheAction" class ="com.spring.LowerAction">
  <property name="message">
   <value>Hello</value>
  </property>
 </bean>
</beans>

测试:

public void testQickStart(){
  ApplicationContext ctx=new FileSystemXmlApplicationContext("bean.xml");
  Action action=(Action)ctx.getBean("TheAction");
  System.out.println(action.execute("Jeff Cheng"));
 }

在spring中的依赖注入有3种实现类型:接口注入、设值注入和构造子注入。所谓依赖注入,就是在运行期由容器将依赖关系注入到组件之中。而程序员只须负责对接口的编程而不必理会接口具体是如何实现的。

一个完整的Bean配置

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
 <description>Spring Bean Configuration Sample</description>
 <bean id="TheAction"
  class="com.spring.UpperAction"
  singleton="true"                                        //是否采用单例
  init-method="init"
  destroy-method="cleanup"
  depends-on="ActionManager">                //是否依赖其他Bean
  <property name="message">
   <value>HeLLo</value>
  </property>
  <property name="dataSource">
   <ref local="dataSource"/>                       //指定属性对其他Bean的引用关系
  </property>
 </bean>


 <bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
  <property name="jndiName">
   <value>java:comp/env/jdbc/sample</value>
  </property>
 </bean>
</beans>

测试代码:

public void testQickStart(){
  ApplicationContext ctx=new FileSystemXmlApplicationContext("bean.xml");
  Action action=(Action)ctx.getBean("TheAction");
  System.out.println(action.execute("Jeff Cheng"));
 }

BeanFactory提供了针对Java Bean的管理功能,而ApplicationContext覆盖了BeanFactory的全部功能并提供了更为框架的实现。

1.国际化支持:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
 <!-- id必须为messageSource -->
 <bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
               <!-- 或ReloadableResourceBundleMessageSource 无需重启加载-->
  <property name="basenames">
   <list>
    <value>messages</value>
   </list>
  </property>
 </bean>
</beans>

Spring会自动在classpath路径中搜索配置文件加载:

messages_zh_CN.properties,messages_zh.properties,message.properties

2.资源访问:Application.getResource("...");

3.事件传播:

可以通过设置listener实现

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
 <description>Spring Login Action</description>
 <bean id="loginaction" class ="com.spring.LoginAction"/>
 <bean id="listener" class="com.spring.ActionListener"/>
</beans>

LoginAction.java:

public class LoginAction implements ApplicationContextAware{
  private ApplicationContext applicationContext;

  public void setApplicationContext(ApplicationContext applicationContext)
   throws BeansException {
   this.applicationContext=applicationContext;
 }
  public int login(String username,String password){
  ActionEvent event=new ActionEvent(username);
  this.applicationContext.publishEvent(event);
  System.out.println("finish");
  return 0;
 }
}

ActionListenser.java:

public class ActionListener implements ApplicationListener{

 public void onApplicationEvent(ApplicationEvent event) {
  if(event instanceof ActionEvent){
   System.out.println(event.toString());
  }
 }
}

ActionEvent.java:

public class ActionEvent extends ApplicationEvent{

 public ActionEvent(Object source) {
  super(source);
 }
}

测试类:

public void testLoginAction(){
  ApplicationContext ctx=new FileSystemXmlApplicationContext("loginBean.xml");
  LoginAction action=(LoginAction)ctx.getBean("loginaction");
  action.login("Jeff Cheng", "mypass");
 }

对于web应用,我们可以在web.xml中配置ContextLoaderListener或ContextLoderServlet

<listener>

  <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>

</listener>

<servlet>  
  <servlet-name>context</servlet-name>  
  <servlet-class>org.springframework.web.context.ContextLoaderServlet</servlet-class>  
  <load-on-startup>1</load-on-startup>  
 </servlet> 

 

Spring高级特性:与MVC框架的整合

MVC框架的运作流程:

1.将Web页面中的输入元素封装成一个请求数据对象。

2.根据请求不同,调度相应的逻辑处理单元,并将请求数据对象作为参数传入。

3.逻辑单元完成运算后,返回一个结果对象。

4.将结果数据对象中的数据与预先设计的表现层相融合并展现给用户。

 

Struts:成熟的设计,丰富的资源和开发群体
Webwork2:设计理念更加先进,代码与Servlet API分离,单元测试便利,BS与CS转换方便,基于对模板技术(Velocity、FreeMarker和XSLT)的支持。
SpringMVC:在依赖注入和AOP方面更加优秀,但MVC框架与底层框架的分离不如webwork,难以脱离servlet容器独立运行。

 

首先来看看与SpringMVC的搭配:

 web.xml容器配置文件
<servlet>
 <servlet-name>Dispatcher</servlet-name>
 <servlet-class>

    org.springframework.web.servlet.DispatcherServlet     //负责调度的核心引擎

 </servlet-class>
 <init-param>
  <param-name>contextConfigLocation</param-name>
  <param-value>/WEB-INF/Config.xml</param-value>
 </init-param>
</servlet>
<servlet-mapping>
 <servlet-name>Dispatcher</servlet-name>
 <url-pattern>*.do</url-pattern>
</servlet-mapping>


spring核心配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<!-- Definition of View Resolver -->
 <bean id="viewResolver" class ="org.springframework.web.servlet.view.InternalResourceViewResolver">
                       <!-- 可选.servlet.view.freemarker.FreeMarkerViewResolver
                         或servlet.view.velocity.VelocityViewResolver -->
  <property name="viewClass">
   <value>org.springframework.web.servlet.view.JstlView</value>
  </property>
  
  <property name="prefix">                   //设定名称前缀
   <value>WEB-INF/view/</value>
  </property>
  
  <property name="suffix">                   //设定名称后缀
   <value>.jsp</value>
  </property>
 </bean>
 
 <bean id="RegisterValidator" class="com.validator.RegisterValidator"/>
 
 <!-- Request Mapping -->
 <bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
  <property name="mappings">
   <props>
    <prop key="/register.do">RegisterAction</prop>
    <prop key="/login.do">LoginAction</prop>
   </props>
  </property>
 </bean>
 
 <!-- Action Definition -->
 <bean id="RegisterAction" class="com.action.RegisterAction">
  <property name="commandClass">
   <value>com.reqbean.RegisterInfo</value>
  </property>
  
  <property name="validator">
   <ref local="RegisterValidator"/>
  </property>
  
  <property name="formView">
   <value>register</value>
  </property>
  
  <property name="successView">
   <value>RegisterSuccess</value>
  </property>
 </bean>
 
 <bean id="LoginAction" class="com.action.LoginAction">
  <property name="commandClass">
   <value>com.action.LoginInfo</value>
  </property>
  
  <property name="fail_view">
   <value>loginfail</value>
  </property>
  
  <property name="success_view">
   <value>main</value>
  </property>
 </bean>
 
 <!-- 对异常进行处理 -->
 <bean id="exceptionResolver" class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
  <property name="defaultErrorView">
   <value>failure</value>
  </property>
  
  <property name="exceptionMappings">
   <props>
    <prop key="java.sql.SQLException">showDBError</prop>
    <prop key="java.lang.RuntimeException">showError</prop>
   </props>
  </property>
 </bean>
 
 <!-- 国际化支持 -->
 <bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
  <property name="basename">
   <value>messages</value>
  </property>
 </bean>
 <!-- 根据浏览器设置语言种类 -->
 <bean id="localeResolver" class="org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver">
 </bean>
 <!-- 根据session设置语言种类
 <bean id="localeResolver" class="org.springframework.web.servlet.i18n.SessionLocalResolver.LOCALE">
 </bean>
  -->
  <!-- 根据cookie设置语言种类
  <bean id="localeResolver" class="org.springframework.web.servlet.i18n.CookieLocaleResolver">
   <property name="cookieName">
    <value>browerLocale</value>//默认为org.springframework.web.servlet.i18n.CookieLocaleResolver.LOCALE
   </property>
   <property name="cookiePath">
    <value>mypath</value>//默认为 /
   </property>
   <property name="cookieMaxAge">
    <value>999999</value>//默认为[2147483647]
   </property>
   -->
</beans>

 

LoginAction.java:

public class LoginAction extends SimpleFormController{
 
 private String fail_view;
 private String success_view;

 protected ModelAndView onSubmit(Object cmd,BindException ex)throws Exception{
  LoginInfo loginInfo=(LoginInfo)cmd;
  
  if(login(loginInfo)==0){
   HashMap result_map=new HashMap();
   result_map.put("logininfo", loginInfo);
   List msgList=new LinkedList();
   msgList.add("msg1");
   msgList.add("msg2");
   msgList.add("msg3");
   
   result_map.put("messages", msgList);
   return new ModelAndView(this.getSuccess_view(),result_map);
  }else{
   return new ModelAndView(this.getFail_view());
  }
 }
 
 private int login(LoginInfo loginInfo){
  if("JeffCheng".equalsIgnoreCase(loginInfo.getUsername())
    &&"123".equals(loginInfo.getPassword())){
   return 0;
  }
  return 1;
 }
 
 public String getFail_view(){
  return fail_view;
 }
 
 public String getSuccess_view(){
  return success_view;
 }
 
 public void setFail_view(String fail_view) {
  this.fail_view = fail_view;
 }

 public void setSuccess_view(String success_view) {
  this.success_view = success_view;
 }

}

RegisterAction.java:

public class RegisterAction extends SimpleFormController{

 protected ModelAndView onSubmit(Object cmd, BindException ex)
   throws Exception {
  Map rsMap=new HashMap();
  rsMap.put("logininfo", cmd);
  return new ModelAndView(this.getSuccessView(), rsMap);
 }
}
RegisterValidator.java:

public class RegisterValidator implements Validator{

 public boolean supports(Class clazz) {
  return RegisterInfo.class.isAssignableFrom(clazz);
 }

 public void validate(Object obj, Errors errors) {
  RegisterInfo regInfo=(RegisterInfo)obj;
  if(regInfo.getUsername().length()<4){
   errors.rejectValue("username","less4chars",null,"用户名长度必须大于4个字母!");
  }
  /*检查用户名是否已经存在
  if(UserDao.getUser(regInfo.getUsername())!=null){
   errors.rejectValue("username","existed",null,"用户已存在");
  }
  */ 
  if(regInfo.getPassword1().length()<6){
   errors.rejectValue("password1","less6chars",null,"密码长度必须大于6个字母!");
  }
  if(!regInfo.getPassword2().equals(regInfo.getPassword1())){
   errors.rejectValue("password2","notsame",null,"两次输入密码不一致!");
  }
 }
}

RegisterInfo.java:

public class RegisterInfo {
 private String username;
 private String password1;
 private String password2;
 
 public String getUsername() {
  return username;
 }
 public void setUsername(String username) {
  this.username = username;
 }
 public String getPassword1() {
  return password1;
 }
 public void setPassword1(String password) {
  this.password1 = password;
 }
 
 public String getPassword2() {
  return password2;
 }
 public void setPassword2(String password) {
  this.password2 = password;
 }
}

 

LoginInfo.java:

public class LoginInfo {
 private String username;
 private String password;
 
 public String getUsername() {
  return username;
 }
 public void setUsername(String username) {
  this.username = username;
 }
 public String getPassword() {
  return password;
 }
 public void setPassword(String password) {
  this.password = password;
 }
}

 

main.jsp:

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

  <body>
    <p>Login Success!</p>
 <p>Current User:
  <c:out value="${logininfo.username}" /><br>
 </p>

 <p>Your current messages:</p>
 <c:forEach items="${messages}" var="item" begin="0" end="9" step="1" varStatus="var">
  <c:choose>
   <c:when test="${var.index%2==0}">
   *
   </c:when>
   <c:otherwise>
   !
   </c:otherwise>
  </c:choose>
  <c:out value="${item}" /><br>
 </c:forEach>
  </body>

 

register.jsp:

<%@ taglib uri="http://java.sun.com/jstl/core" prefix="c"%>
<%@ taglib uri="http://www.springframework.org/tags" prefix="spring"%>

  <body style="text-align:center">
 <form action="/SpringMVC/register.do" method="post">
  <spring:bind path="command.*">
   <font color="#FF0000">
    <c:forEach items="${status.errorMessages}" var="error">
     <spring:message code="error_msg" /><c:out value="${error}" /><br>
    </c:forEach>
   </font>
  </spring:bind>
  <table border="0" width="450" height="101" cellspacing="0" cellpadding="0">
   <tr>
    <td height="27" width="408" colspan="2">
     <p align="center"><b><spring:message code="register_title" /></b></td>
   </tr>

   <tr>
    <td height="23" width="104"><spring:message code="username_label" />:</td>
    <td height="23" width="450">
     <spring:bind path="command.username">
      <input type="text"
       value="<c:out value='${status.value}'/>"
       name="<c:out value='${status.expression}'/>">
      (<spring:message code="less4chars" />)
      <br>
      <c:if test="${status.error}">
       <font color="#FF0000">
        <spring:message code="error_msg" />
        <c:forEach items="${status.errorMessages}" var="error">
         <c:out value="${error}"/>
        </c:forEach>
       </font>
      </c:if>
     </spring:bind>
    </td>
    
   </tr>

   <tr>
    <td height="23" width="104"><spring:message code="password_label" />:</td>
    <td height="23" width="450">
    <spring:bind path="command.password1">
      <input type="password"
       value="<c:out value='${status.value}'/>"
       name="<c:out value='${status.expression}'/>">
      (<spring:message code="less6chars" />)
      <br>
      <c:if test="${status.error}">
       <font color="#FF0000">
        <spring:message code="error_msg" />
        <c:forEach items="${status.errorMessages}" var="error">
         <c:out value="${error}"/>
        </c:forEach>
       </font>
      </c:if>
     </spring:bind>
    </td>
   </tr>

   <tr>
    <td height="23" width="104"><spring:message code="rep_pass_label" />:</td>
    <td height="23" width="450">
    <spring:bind path="command.password2">
      <input type="password"
       value="<c:out value='${status.value}'/>"
       name="<c:out value='${status.expression}'/>">
      <br>
      <c:if test="${status.error}">
       <font color="#FF0000">
        <spring:message code="error_msg" />
        <c:forEach items="${status.errorMessages}" var="error">
         <c:out value="${error}"/>
        </c:forEach>
       </font>
      </c:if>
     </spring:bind>
    </td>
   </tr>

  </table>
 <p>
  <input type="submit" value="提交" name="B1">
  <input type="reset" value="重置" name="B2">
 </p>
 </form>   
  </body>

 

RegisterSuccess.jsp:

<body>
 <p align="center">
  <c:out value="${logininfo.username}"/>注册成功!
 </p>
  </body>

 

showError.jsp:

<body>
 <%Exception ex=(Exception)request.getAttribute("Exception"); %>
 <h2>Exception:<%ex.getMessage(); %></h2>
 <p/>
 <%ex.printStackTrace(new java.io.PrintWriter(out)); %>
  </body>

 

模版技术:

XSLT:基于XML的表现层模版技术,移植性强,界面开发难度大,语法复杂,调试难度大,性能比较低下,内存占用较大
Velocity:最为成熟的模版技术,得到广泛的应用。
FreeMarker:表现逻辑和业务逻辑划分严格,模板不允许对Servlet API直接操作,禁止对HttpServletRequest对象直接访问,保证了层次间的清晰。提供了对JSP Tag的良好的支持,在生产效率和学习成本上具有优势。

下面用FreeMarker来改造上面的例子:

Config.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
 <!-- Definition of View Resolver -->
 <bean id="viewResolver" class ="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
  <property name="viewClass">
   <value>org.springframework.web.servlet.view.freemarker.FreeMarkerView</value>
  </property>
  
  <property name="cache">
   <value>false</value>
  </property>
  
  <property name="suffix">
   <value>.ftl</value>
  </property>
 </bean>
 
 <bean id="freemarkerConfig" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
  <property name="templateLoaderPath">
   <value>WEB-INF/view/</value>
  </property>
 </bean>
 
 <!-- Request Mapping -->
 <bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
  <property name="mappings">
   <props>
    <prop key="/login.do">LoginAction</prop>
   </props>
  </property>
 </bean>
 
 <!-- Action Definition -->
 <bean id="LoginAction" class="com.action.LoginAction">
  <property name="commandClass">
   <value>com.action.LoginInfo</value>
  </property>
  
  <property name="fail_view">
   <value>loginfail</value>
  </property>
  
  <property name="success_view">
   <value>main</value>
  </property>
 </bean>
</beans>

main.ftl:

<html>
<head>
 <title>Welcome!</title>
</head>
<body>
 <h1>Current User:${logininfo.username}</h1>
 <#list messages as msg>
  <#if msg_index%2=0>
   *
  <#else>
   !
  </#if>
  ${msg}<br>
 </#list>
</body>
</html>