SpringMVC设计模型替换struts测试
首先转载
第一、MVC框架的出现是为了将URL从HTTP的世界中映射到Java世界中,这是MVC框架的核心功能。而在URL这一点SpringMVC无疑更加优雅。
第二、从设计实现角度来说,我觉得SpringMVC更加清晰。即使我们去对比Struts2的原理图和SpringMVC的类图,它依然很让人困惑,远没有SpringMVC更加直观。
SpringMVC设计思路:将整个处理流程规范化,并把每一个处理步骤分派到不同的组件中进行处理。
这个方案实际上涉及到两个方面:
l 处理流程规范化 —— 将处理流程划分为若干个步骤(任务),并使用一条明确的逻辑主线将所有的步骤串联起来
l 处理流程组件化 —— 将处理流程中的每一个步骤(任务)都定义为接口,并为每个接口赋予不同的实现模式
处理流程规范化是目的,对于处理过程的步骤划分和流程定义则是手段。因而处理流程规范化的首要内容就是考虑一个通用的Servlet响应程序大致应该包含的逻辑步骤:
l 步骤1—— 对Http请求进行初步处理,查找与之对应的Controller处理类(方法) ——HandlerMapping
l 步骤2—— 调用相应的Controller处理类(方法)完成业务逻辑 ——HandlerAdapter
l 步骤3—— 对Controller处理类(方法)调用时可能发生的异常进行处理 ——HandlerExceptionResolver
l 步骤4—— 根据Controller处理类(方法)的调用结果,进行Http响应处理 ——ViewResolver
第三、设计原则更加明朗。
【Open for extension /closed for modification】
这条重要的设计原则被写在了spring官方的reference中SpringMVC章节的起始段: A key design principle in SpringWeb MVC and in Spring in general is the “Open for extension, closed for modification” principle.
并且重点很好地体现在SpringMVC的实现当中,可以扩展,但却不能改变。我曾经扩展过Spring的IOC、AOP功能,这一点SpringMVC应该和Spring一脉相承。
第四、组件化的设计方案和特定的设计原则让SpringMVC形散神聚。
- 神 —— SpringMVC总是沿着一条固定的逻辑主线运行
- 形 —— SpringMVC却拥有多种不同的行为模式
SpringMVC是一个基于组件的开发框架,组件的不同实现体系构成了“形”;组件的逻辑串联构成了“神”。因此,“形散神不散”: SpringMVC的逻辑主线始终不变,而行为模式却可以多种多样。
第五、更加贴合Web发展的趋势,这个更加虚了,不再展开说这个 问题了。
第六、技术上的放缓导致了程序员对Struts2失去了热情,导致SpringMVC依靠自身的努力和Spring的口碑,逐渐显露了自身的优势和特点。
为什么SpringMVC会赢得最后的胜利呢?最后,我们不妨想一想Struts2是怎样流行起来的!
我自己是从Struts1用过来的,后来Struts1的问题很明显了,开源社区出现了很多的MVC框架,最为突出的是Webwork2。
Webwork2探索了一条与传统Servlet模型不同的解决方案,逐渐被大家熟识和理解,不断发展并得到了广大程序员的认可。它以优秀的设计思想和灵活的实现,吸引了大批的Web层开发人员投入它的 怀抱。
Apache社区与Opensymphony宣布未来的Struts项目将与Webwork2项目合并,并联合推出Struts2。
Struts2能够在一个相当长的时间段内占据开发市场主导地位的重要原因在于其技术上的领先优势。而这一技术上的领先优势,突出表现为对Controller的彻底改造:
public class UserController {
private User user
public String execute() {
// 这里加入业务逻辑代码
return "success";
}
}
从上面的代码中,我们可以看到Webwork2 /Struts2对于Controller最大的改造有两点:
- 在Controller中彻底杜绝引入HttpServletRequest或者HttpServletResponse这样的原生Servlet对象。
- 将请求参数和响应数据都从响应方法中剥离到了Controller中的属性变量。
这两大改造被看作是框架的神来之笔。因为通过这一改造,整个Controller类彻底与Web容器解耦,可以方便地进行单元测试。而摆脱了Servlet束缚的Controller,也为整个编程模型赋予了全新的定义。从引入新的编程元素的角度来说,Webwork2 / Struts2无疑也是成功的。因为在传统Servlet模式中的禁地Controller中的属性变量被合理利用了起来作为请求处理过程中的数据部分。这样的改造不仅使得表达式引擎能够得到最大限度的发挥,同时使得整个Controller看起来更像是一个POJO。因而,这种表现形态被笔者冠以的名称 是:POJO实现模式。POJO实现模式是一种具有革命性意义的模式,因为它能够把解耦合这样一个观点发挥到极致。从面向对象的角度来看,POJO模式无疑也是所有程序员所追求的一个目标。这也就是Webwork2 /Struts2那么多年来经久不衰的一个重要原因。
下面是测试代码部分
applicationContext.xml配置
<span style="font-size:18px;"><!-- 扫描包内的注解 -->
<context:component-scan base-package="com.hellojava"></context:component-scan>
<!-- 注册驱动类 -->
<mvc:annotation-driven/>
<!-- 视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/view/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
<!-- 配置数据源 -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/mytest3"></property>
<property name="username" value="root"></property>
<property name="password" value="1111"></property>
</bean>
<!-- 集成myBaits框架,配置sqlSessionFatory -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<property name="typeAliasesPackage" value="com.hellojava.entity"></property>
<property name="mapperLocations" value="classpath:com/hellojava/mapper/*.xml"></property>
</bean>
<!-- mybatis自动扫描包下的mapper -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.hellojava.dao"></property>
<property name="sqlSessionFactory" ref="sqlSessionFactory"></property>
</bean></span>
web.xml配置文件
<span style="font-size:18px;"><!-- The front controller of this Spring Web application, responsible for handling all application requests -->
<servlet>
<servlet-name>springDispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param><!-- spring 容器 spring配置文件的路径 -->
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</init-param><!-- 修改servlet初始化时机 -->
<load-on-startup>1</load-on-startup>
</servlet>
<!-- Map all requests to the DispatcherServlet for handling -->
<servlet-mapping>
<servlet-name>springDispatcherServlet</servlet-name>
<url-pattern>/</url-pattern><!-- 过滤全部请求 -->
</servlet-mapping>
<filter><!-- 处理文字请求 -->
<filter-name>characterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping></span>
项目测试各个包及其文件如下
业务层
package com.hellojava.business;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.hellojava.dao.BookDao;
import com.hellojava.entity.Book;
@Service("bookService")
public class BookService {
@Autowired
private BookDao bookDao;
public List<Book> loadAll(){
return bookDao.loadAll();
}
public boolean save(Book book){
int i=bookDao.save(book);
return i>0?true:false;
}
public boolean delete(int bookId){
int i=bookDao.delete(bookId);
return i>0?true:false;
}
public Book loadById(int bookId){
return bookDao.loadById(bookId);
}
public boolean update(Book book){
int i=bookDao.update(book);
return i>0?true:false;
}
}
package com.hellojava.contorller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Required;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import com.hellojava.business.BookService;
import com.hellojava.entity.Book;
@Controller
public class BookContorller {
@Autowired
private BookService bookService;
@RequestMapping("/loadAll")
public String loadAll(ModelMap model){
List<Book> books=bookService.loadAll();
model.addAttribute("books",books);
return "index";
}
@RequestMapping("/save.html")
public String save(){
return "save";
}
@RequestMapping("/saveHander")
public String saveHander(Book book){
boolean bool=bookService.save(book);
return bool?"redirect:/loadAll":"error";
}
@RequestMapping("/deleteHander")
public String deleteHander(int bookId){
boolean bool=bookService.delete(bookId);
return bool?"redirect:/loadAll":"error";
}
@ModelAttribute
public void loadBook(@RequestParam(name="bookId",required=false) Integer bookId,ModelMap model){
if(bookId!=null){
Book book= bookService.loadById(bookId);
model.addAttribute("book", book);
}
}
@RequestMapping("/loadUpdate")
public String loadById(int bookId,ModelMap model){
Book b=bookService.loadById(bookId);
model.addAttribute("loadUpdate", b);
return "update";
}
@RequestMapping("/updateHander")
public String update(@RequestParam("book")Book book){
return "redirect:/loadAll";
}
}
映射文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.hellojava.dao.BookDao">
<select id="loadAll" resultType="Book">
select * from Book
</select>
<insert id="save" parameterType="Book">
insert into book(bookName,bookAuthor,bookPrice,bookInfo)
values(#{bookName},#{bookAuthor},#{bookPrice},#{bookInfo})
</insert>
<delete id="delete" parameterType="int">
delete from book where bookId=#{bookId}
</delete>
<select id="loadById" parameterType="int" resultType="Book">
select * from book where bookId=#{bookId}
</select>
<update id="update" parameterType="Book">
update book set bookName=#{bookName},bookAuthor=#{bookAuthor},bookPrice=#{bookPrice},bookInfo=#{bookInfo} where bookId=#{bookId}
</update>
</mapper>