@Action public class ProductAction { @Request("GET:/product") public Page index() { ...... } @Request("POST:/product/create") public Result create(Map<String, Object> fieldMap, List<Multipart> multipartList) { ...... } @Request("PUT:/product/update/{id}") public Result update(long id, Map<String, Object> fieldMap) { ...... } @Request("DELETE:/product/delete/{id}") public Result delete(long id) { ...... } }
public Page index(); public Result delete(long id) public Page search(Map<String, Object> fieldMap) public Result update(long id, Map<String, Object> fieldMap) public Result create(List<Multipart> multipartList) public Result create(Map<String, Object> fieldMap, List<Multipart> multipartList) public Result uploadPicture(long id, Map<String, Object> fieldMap, List<Multipart> multipartList) ......
Action方法返回值容许为void、Page、Result三种。 java
a. 以void为返回值的方法,处理完业务后,不作后续操做,例以下载等。 mysql
b. 以Page为返回值的方法,则转发或重定向到相应的页面中。 ajax
Page经常使用方法: sql
void setPath(String path);//设置路径 void setData(Map<String, Object> data);//设置参数
c. 以Result为返回值的方法,则返回包含基本信息的json字符串。 数据库
Result经常使用方法: json
void setSuccess(boolean success);//设置成功标志 void setError(int error);//设置错误代码 void setData(Object data);//设置响应数据
借鉴 Spring IOC 的思路,可将任意的类标注为@Bean,当应用启动时,框架会自动建立这些 Bean实例,并放入容器中。随后可以使用 BeanHelper.getBean() 方法获取对应的 Bean实例。通常状况下,会将 Action类标注为@Action,Service实现类标注为 @Service,可在 Action类中使用 @Inject注解注入所需的 Service接口。 app
Action类: @Action public class ProductAction { @Inject private ProductService productService; ... } Service 实现类: @Service public class ProductServiceImpl implements ProductService { ... }若在项目中一个接口同时存在多个实现类,此时只能选择其中的一个实现类生效,可在接口上使用 @Impl指定具体的实现类。
方法 框架 |
说明 jsp |
void begin() ide |
在进入方法时执行。 |
boolean intercept(Method method, Object[] args) |
设置过滤条件。默认返回 true,表示无过滤条件。 |
void before(Method method, Object[] args) |
在目标方法调用前执行。 |
void after(Method method, Object[] args) |
在目标方法调用后执行。 |
void error(Method method, Object[] args, Exception e) |
在抛出异常时执行。 |
void end() |
在方法执行完毕前执行。 |
如下编写了一个 Aspect 类,用于横切 com.smart.sample.action下全部类的方法,除了SystemAction类,代码以下:
@Aspect(pkg = "com.smart.sample.action") @Order(0) public class AccessAspect extends AspectProxy { @Override public boolean intercept(Class<?> cls, Method method, Object[] params) throws Exception { boolean result = true; if (cls == SystemAction.class) { result = false; } return result; } @Override public void before(Class<?> cls, Method method, Object[] params) throws Exception { Long userId = DataContext.Session.get(Constant.USER_ID); if (userId == null) { WebUtil.setRedirectURL(DataContext.getRequest(), Constant.REDIRECT_URL); throw new AccessException(); } } }可在 intercept() 方法中,对目标方法(Method 对象)的名称、参数、返回值、注解等信息设置过滤条件。
public class Product extends BaseEntity { private long productTypeId; private String productName; private String productCode; private int price; private String description; ... getter/setter 方法 }
映射规则以下:
Entity 类 |
数据库 |
类名(如:Product) |
表名(如:product) |
属性名(如:productTypeId) |
列名(如:product_type_id) |
可见,将 Entity 类的类名与属性名的“驼峰式”转为“下划线式”,即为数据库的表名与列名。若表名带有前缀(如:t_product),则此时须要借助 @Table 注解,将其标注在 Entity 类上,在该注解的参数中指定所对应的表名(如:@Table(“t_product”))。
同理,对于属性名与列名的不规则映射规则,能够借助 @Column 注解实现映射关系。当列名为 Java 关键字时(如:class),须要考虑此方案。
在本框架中使用“贫血式”模型,不使用 OneToMany、ManyToOne、ManyToMany 等“充血式”模型,也就是说,一个 Entity 与一个 Table 对应,一个 Property 与一个 Column 对应。建议使用 Java 原始类型,而不是封装类型,如:建议使用 int,而不是 Integer。
Entity 属性类型只能从如下类型中选择:
类型 |
说明 |
int |
对于长度较小的数值类型数据,推荐使用 int 类型,不要使用 Integer 类型。 |
long |
对于长度较长的数值类型数据,推荐使用 long 类型,不要使用 Long 类型。 |
double |
对于全部的浮点类型数据,推荐使用 double 类型,不要使用 Double、float/Float 等类型。 |
String |
对于字符类型数据,推荐使用 String 类型,不要使用 char 类型。 |
注意:对于日期或时间,推荐使用 String 或 long 类型,而不要使用 Date 类型。
@Action public class ProductAction { @Inject private ProductService productService; ... @Request("get:/product/{id}") public Result getProductById(long productId) { if (productId == 0) { return new Result(false).error(ERROR_PARAM); } Product product = productService.getProduct(productId); if (product != null) { return new Result(true).data(product); } else { return new Result(false).error(ERROR_DATA); } } ... }当 productId 为 0 时,返回一个 Result 对象,成功标志为 false,错误代码 ERROR_PARAM(值为 10)。错误代码可统必定义。
... $.ajax({ url: '/product/' + productId, type: 'get', success: function(result) { if (result.success) { var product = result.data; $('#product_type_id').val(product.productTypeId); $('#product_name').val(product.productName); $('#product_code').val(product.productCode); $('#price').val(product.price); $('#description').val(product.description); } else { switch (result.error) { case 10: alert('The parameter is error!'); break; case 20: alert('The data is error!'); break; } } } }); ...
public class ProductServiceTest extends BaseTest { private ProductService productService = BeanHelper.getBean(ProductServiceImpl.class); @BeforeClass @AfterClass public static void init() { initSQL("sql/product.sql"); } @Test @Order(1) public void getProductListTest() { List<Product> productList = productService.getProductList(); Assert.assertNotNull(productList); Assert.assertEquals(productList.size(), 7); } @Test @Order(2) public void getProductTest() { long productId = 1; Product product = productService.getProduct(productId); Assert.assertNotNull(product); } ... }Test 类必须继承 BaseTest 类。在类中可以使用 BeanHelper.getBean() 方法初始化相关的 Bean 实例(这里是 Service 实现类实例),注意:此时不能使用 @Inject 实现依赖注入。可以使用 JUnit 提供的 @Test、@BeforeClass、@AfterClass 等注解来标注被测方法。在 init() 方法上同时标注了 @BeforeClass 与 @AfterClass,表示该方法会在测试以前与测试以后被 JUnit 框架所调用,用于执行数据初始化脚本,该脚本在 test/resources/sql/ 目录下。
#应用名称 app.name=smart-sample #Action类所在的包 app.package=com.smart.sample #网站静态资源路径 app.www_path=/www/ #jsp路径 app.jsp_path=/WEB-INF/jsp/ #登陆地址 app.home_page=/login #上传文件尺寸大小(MB) app.upload_limit=10 #数据库类型 jdbc.type=mysql #驱动名 jdbc.driver=com.mysql.jdbc.Driver #数据库连接地址 jdbc.url=jdbc:mysql://localhost:3306/sample #登陆名 jdbc.username=root #密码 jdbc.password=root #是否动态加载i18n文件 i18n.reloadable=true #上传路径 sample.upload_path=/www/upload/