本文是《轻量级 Java Web 框架架构设计》的系列博文。
前面谈到了一些框架的实现原理,现在是时候用一把这个框架了。对了,此框架现命名为 Smart Framework。我希望它和您想象得一样 Smart!
开始行动吧!
打开你心爱的代码编辑器(我用的是 IDEA)。使用 Maven 创建一个 Web 项目,初始代码目录如下:
包名是 com.smart.sample,这个倒无所谓了。需要注意的是,我将 WEB-INF 下的 web.xml 文件给删掉了!
没有 web.xml 还是 Web 应用吗?是的!这是基于 Servlet 3.0 的规范,web.xml 可以不要了,统一采用注解的方式来编写 Servlet。现在我们还需要编写 Servlet 吗?不需要了,因为我们已经有 Smart 了。
简单看看 Maven 配置文件 pom.xml 吧:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.smart</groupId> <artifactId>smart-sample</artifactId> <version>1.0</version> <packaging>war</packaging> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <dependencies> <!-- JUnit --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency> <!-- Smart --> <dependency> <groupId>com.smart</groupId> <artifactId>smart-framework</artifactId> <version>1.0</version> </dependency> </dependencies> <build> <finalName>smart-sample</finalName> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-war-plugin</artifactId> <version>2.4</version> <configuration> <failOnMissingWebXml>false</failOnMissingWebXml> </configuration> </plugin> </plugins> </build> </project>就依赖于两个包,JUnit 是为了做单元测试用的,另外一个就是 Smart 了。需要注意的是,由于没有 web.xml 会导致 Maven 执行 package 时报错,需要手工配置 maven-war-plugin 插件,将 failOnMissingWebXml 设置为 false。
好了,代码框架搭建完毕,下面我们不妨来做一下数据库设计吧。我用的是 MySQL 数据库,客户端是 Navicat。
先就搞一张很简单的表 product,表结构如下:
再手工录一点数据吧,后面测试的时候也好有个效果,表数据如下图:
一般定义数据库表结构都是有团队中水平比较高的人,比如:架构师或 DBA 来负责的,我们程序员拿到的就是一份数据库脚本,甚至是一个数据库连接,在好的情况下,我们还可以拿到一份数据字典(Excel 格式的最爽了)。
下面才是我们程序员要干的活了,根据表结构创建实体(Entity)。既然表名是 product,为了好理解,不妨将实体名定义为 Product。其实无需这样,假如表名是 abc,实体名也可以定义成 Product。不过最好在团队内部有相应的开发规范作为约束。
废话少说,先来一个 Product 实体:
public class Product extends BaseEntity { private long productTypeId; private String productName; private String productCode; private int price; private String description; public long getProductTypeId() { return productTypeId; } public void setProductTypeId(long productTypeId) { this.productTypeId = productTypeId; } ... }
Product 类继承于 BaseEntity,那么它就是一个 Entity 了,无需任何注解,但字段名命名一定要按照规范,例如:字段 productTypeId 对应列名 product_type_id。下面的 getter/setter 方法太多,我就省略了。
实体有了,现在我们来做一个接口吧,就定义一个方法好了。根据 Product ID 获取 Product 对象,这类代码应该每个程序员都写过吧?
public interface ProductService { Product getProduct(long productId); }
接口定义好了,直接写实现类吧:
@Bean public class ProductServiceImpl extends BaseService implements ProductService { @Override public Product getProduct(long productId) { String sql = SQLHelper.getSQL("select.product.id"); return DBHelper.queryBean(Product.class, sql, productId); } }
是不是很简洁?有四件事情需要注意:
1. 在实现类上标注 @Bean 注解,这样它就交给 Bean 容器管理了(类似于 Spring 的 @Component)。
2. 扩展 BaseService 类(这个类有什么作用,以后再说)。
3. 使用 SQLHelper 获取 SQL 语句(实际上就是一个 SQL 语句模板,里面是带有“?”占位符的)。
4. 使用 DBHelper 执行数据库操作,该方法直接返回 JavaBean(将来也会返回 Map,以后会实现的)。
关于 SQL 语句,需要统一编写在 sql.properties 文件中:
select.product.id = select * from product where id = ?
好了,实现类开发完毕。下面就轮到 Action 上场了:
@Bean public class ProductAction extends BaseAction { @Inject private ProductService productService; @Request("GET:/product/{id}") public Result getProductById(long productId) { if (productId == 0) { return new Result(ERROR_PARAM); } Product product = productService.getProduct(productId); if (product != null) { return new Result(OK, product); } else { return new Result(ERROR_DATA); } } }
这里同样有四件事情需要注意:
1. Action 同样也使用了 @Bean 注解,也就是说,将 Action 交给依赖注入容器(或称为 Bean 容器)进行管理,由容器来为我们创建实例。
2. 这里还通过 @Inject 注解注入了一个 ProductService 接口,实现类到底是什么?Smart Framework 会为我们寻找。
3. 使用 @Request 注解,将请求 URL 与 Action 方法进行映射(是不是比 Spring MVC 的注解要来得简单呢?)。注意:URL 中占位符的顺序,一定要与方法中参数的顺序保持一致,数量上也要相等,否则无法正确匹配。
4. Action 的返回值统一使用 Result 对象,这个类封装了错误代码(int error)与返回数据(Object data)。在 Result 中使用了一些常量类,例如:ERROR_PARAM,这些常量都在 BaseAction 中定义好了。
后端到目前为止,已全部开发完毕,开启您的 Tomcat 吧。
没有报错,那就打开您的浏览器,输入一个请求看看效果,请求:http://localhost:18080/product/1
结果成功返回了!
为了看清整个代码目录结构,有必要贴一张图:
总结一下,程序要做的只有四件事情:
1. 编写 Entity,例如:Product。
2. 编写接口及其实现类,例如:ProductService 与 ProductServiceImpl。
3. 编写 SQL 语句,统一写在 sql.properties 文件中。
4. 编写 Action,例如:ProductAction。
最后,还有一份配置文件 config.properties,它一般不需要频繁修改,有关 JDBC 连接属性都在里面,我就不贴出来了。
由于个人水品有限,或许会存在不少错误,期待您的留言!