LastaFlute Action
URL Mapping
You can know the URL from the action name.
Mapping Convention (Big convention)
- Request URL
- Action class + Execute method
Mapping Example
- ProfilePasswordAction#change()
- /profile/password/change/
- ProductAction#list()
- /product/list/
- ProductListAction#index()
- /product/list/
- MypageAction#index()
- /mypage/
- RootAction#index()
- / ※Special Action means URL '/'
Action Package
- ProfilePasswordAction#change()
- /profile/password/change/
- ProductAction#list()
- /product/list/
- ProductListAction#index()
- /product/list/
- MypageAction#index()
- /mypage/
- RootAction#index()
- / ※Special Action means URL '/'
Action Package
You can just know the location of action from the name.
Package Convention
- Application Package
- [your domain].app e.g. org.docksidestage.app
- Web Package
- [Application Root].web e.g. org.docksidestage.app.web
- Action's Package
- *you can use Action's prefix package
Package Example
You can choose several pattern like this: e.g. ProfilePasswordAction
- [Application Root].web.ProfilePasswordAction#change()
- [Application Root].web.profile.ProfilePasswordAction#change() *recommended
- [Application Root].web.profile.password.ProfilePasswordAction#change()
e.g. Action Class Package Location @Directory
org.docksidestage
|-app // Application Package
| |-logic
| |-web // Web Package
| |-product
| | |-ProductListAction
| | |-ProductPurchaseAction
| |-profile
| | |-ProfilePasswordAction
| | |-ProfileWithdrawalAction
| |-mypage
| | |-MypageAction
| |-RootAction
|-dbflute
| |-allcommon
| |-bsbhv
| |-...
|-mylasta
| |-action
| |-direction
| |-...
make Action Class
arguments and return value for IN/OUT
Action Defintion
- Super Class
- extends [App]BaseAction
- Behavior DI
- instance variable with @Resource
- Execute Method
- public method with @Execute
e.g. Action Class Definition @Java
public class ProductListAction extends DocksideBaseAction { // Super Class
@Resource
private ProductBhv productBhv; // Behavior DI
@Execute
public HtmlResponse index() { // Execute Method
...
}
}
URL Parameter
e.g. ProductListAction#index()
e.g. accept URL parameter as required argument @Java
@Execute
public HtmlResponse index(int pageNumber) { // /product/list/3
...
}
e.g. accept URL parameter as optional argument @Java
@Execute
public HtmlResponse index(OptionalThing<Integer> pageNumber) {
pageNumber.ifPresent(() -> { // /product/list/3
...
}).orElse(() -> { // /product/list/
...
});
}
e.g. accept URL parameter with more URL @Java
// /product/list/mystic/ikspiary/oneman/ (sea=mystic, land=oneman)
@Execute(urlPattern = "{}/ikspiary/{}")
public HtmlResponse index(String sea, String land) {
...
}
Action Form (for POST, GET parameter)
e.g. accept POST parameter by action form @Java
@Execute
public HtmlResponse doSignin(ProductSearchForm form) { // POST (or also GET)
...
}
e.g. both URL parameter and GET parameter @Java
// e.g. /.../list/3?favoriteCode=sea&nextName=land
@Execute
public HtmlResponse index(int pageNumber, ProductSearchForm form) {
...
}
You can use Validator Annotation for basic validation. e.g. Required, Max... (then you should call the validate() method in execute method of action)
e.g. validator annotation in form @Java
public class ProductEditForm {
@Required
public String productName;
}
And you can basic native type for bean properties. e.g. Integer, LocalDate, CDef...
e.g. native type for properties in form @Java
public class ProductSearchForm {
public Integer productId;
public String productName;
public CDef.ProductStatus productStatus;
}
JSON Body (for JSON in request body)
e.g. accept JSON in request body by JSON body @Java
@Execute
public JsonResponse<ProductBean> index(ProductSearchBody body) {
...
}
It can be treated as action form, e.g. can use validation, native type properties
e.g. body for product search @Java
public class ProductSearchBody {
public Integer productId;
public String productName;
@Required
public CDef.ProductStatus productStatus;
}
Action Response
- HtmlResponse
- asHtml(path_...) or redirect(...class)
- JsonResponse
- asJson(bean)
- StreamResponse
- asStream(ins)
e.g. HtmlResponse @Java
@Execute
public HtmlResponse index() {
...
return asHtml(path_MyPage_MyPageJsp);
}
@Execute
public HtmlResponse doUpdate() {
...
return redirect(MypageAction.class);
}
e.g. JsonResponse @Java
@Execute
public JsonResponse<ProductBean> product() {
ProductBean bean = ...
return asJson(bean);
}
Form/Body Validation
You can use Hibernate Validator's annotations in form or body.
e.g. validator annotation in form @Java
public class ProductEditForm {
@Required
public String productName;
}
And you should call in your action.
e.g. validation as HTML response @Java
@Execute
public HtmlResponse index(OptionalThing<Integer> pageNumber
, ProductSearchForm form) {
validate(form, messages -> {}, () -> {
return asHtml(path_Product_ProductListJsp);
});
...
}
e.g. validation as JSON response @Java
@Execute
public JsonResponse<SearchPagingBean<ProductRowBean>> index(
OptionalThing<Integer> pageNumber
, ProductSearchBody body) {
validate(form, messages -> {});
...
}
Specify more validation manually at second argument.
e.g. more validation @Java
@Execute
public JsonResponse<SearchPagingBean<ProductRowBean>> index(
OptionalThing<Integer> pageNumber
, ProductSearchBody body) {
validate(form, messages -> {
if (body.productName == null) {
messages.addConstraintsRequiredMessage("productName");
}
});
...
}
Example Code
HTML response style
e.g. Action for URL '/product/list/3' as HTML response @Java
@Execute
public HtmlResponse index(OptionalThing<Integer> pageNumber
, ProductSearchForm form) {
validate(form, messages -> {}, () -> {
return asHtml(path_Product_ProductListJsp);
});
PagingResultBean<Product> page = productBhv.selectPage(cb -> {
cb.setupSelect_ProductStatus();
cb.query().setProductName_LikeSearch(form.productName, op -> op.likeContain());
cb.query().addOrderBy_ProductName_Asc();
cb.paging(getPagingPageSize(), pageNumber.orElse(1));
});
List<ProductRowBean> beans = page.mappingList(product -> {
return mappingToBean(product);
});
return asHtml(path_Product_ProductListJsp).renderWith(data -> {
data.register("beans", beans);
registerPagingNavi(data, page, form);
});
}
JSON response style
e.g. Action for URL '/product/list/3' as JSON response @Java
@Execute
public JsonResponse<SearchPagingBean<ProductRowBean>> index(
OptionalThing<Integer> pageNumber
, ProductSearchBody body) {
validate(body, messages -> {});
ListResultBean<Product> page = productBhv.selectPage(cb -> {
cb.setupSelect_ProductStatus();
cb.query().setProductName_LikeSearch(form.productName, op -> op.likeContain());
cb.query().addOrderBy_ProductName_Asc();
cb.paging(getPagingPageSize(), pageNumber.orElse(1));
});
SearchPagingBean<ProductRowBean> bean = createPagingBean(page);
return asJson(bean);
}
TemplatePath FreeGen (if use)
At first, make template file (e.g. JSP) (empty file for now)
- File Name
- related to URL form tag submits ※except buttom name
- Location Directory
- prefix of file name
URL requested by la:form tag when action attribute is omitted.
- product/product_list.jsp
- /product/list/
- profile/profile_password_change.jsp
- /profile/password/change/
- mypage/mypage.jsp
- /mypage/
Execute FreeGen task of DBFlute, and you can complement the generated path definition in your code.
e.g. Template File Location @Directory
src/main/webapp
|-WEB-INF
|-view // location for HTML templates
| |-product // related to product package
| | |-product_list.jsp // /product/list/
| | |-product_purchase.jsp // /product/purchase/
| |
| |-profile
| | |-profile_password_change.jsp // /profile/password/change/
| | |-profile_withdrawal.jsp // /profile/withdrawal/
| |
| |-mypage
| | |-mypage.jsp // /mypage/
| |
| |-root.jsp // '/'
|
|-web.xml
e.g. you can use Template Path for HtmlResponse @Java
@Execute
public HtmlResponse index() {
...
return asHtml(path_Mypage_MypageJsp); // is static definition
}