Brutos Framework
The Brutos Framework (Brutos Application Framework) is MVC controller developed in Java. Designed to reduce the complexity of web development, with configurable mapping, view resolution as well as support for Uploading and downloading files. Can be configured using XML, annotations and CoC.
The framework follows the below principles:
- Flexibility;
- low coupling;
- Productivity.
Examples
Quick Start
pom.xml
...
<dependencies>
<dependency>
<groupId>org.brandao</groupId>
<artifactId>brutos-core</artifactId>
<version>2.0-b5</version>
</dependency>
<dependency>
<groupId>org.brandao</groupId>
<artifactId>brutos-web</artifactId>
<version>2.0-b5</version>
</dependency>
<dependency>
<groupId>org.brandao</groupId>
<artifactId>brutos-annotation</artifactId>
<version>2.0-b5</version>
</dependency>
</dependencies>
...web.xml
...
<listener>
<listener-class>org.brandao.brutos.web.ContextLoaderListener</listener-class>
</listener>
<filter>
<filter-name>Brutos Framework Filter</filter-name>
<filter-class>org.brandao.brutos.web.http.BrutosRequestFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>Brutos Framework Filter</filter-name>
<url-pattern>*</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
<dispatcher>INCLUDE</dispatcher>
<dispatcher>ERROR</dispatcher>
</filter-mapping>
...brutos-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<controllers xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
xmlns='http://www.brutosframework.com.br/schema/controllers'
xmlns:context='http://www.brutosframework.com.br/schema/context'
xsi:schemaLocation='
http://www.brutosframework.com.br/schema/controllers
http://www.brutosframework.com.br/schema/controllers/brutos-controllers-1.1.xsd
http://www.brutosframework.com.br/schema/context
http://www.brutosframework.com.br/schema/context/brutos-context-1.1.xsd'>
</controllers>Creating a simple controller
URI mapping:
Controller/Action |
URI |
View |
|---|---|---|
| IndexController |
/Index |
/WEB-INF/index/index.jsp |
| IndexController.defaultAction() |
/Index/default |
/WEB-INF/index/defaultaction/index.jsp |
Controller
public class IndexController{
public void defaultAction(){
...
}
}Defining the path of controller
URI mapping:
Controller/Action |
URI |
View |
|---|---|---|
| IndexController |
/mycontroller |
/WEB-INF/index/index.jsp |
| IndexController.defaultAction() |
/mycontroller/default |
/WEB-INF/index/defaultaction/index.jsp |
Controller
@Controller("/mycontroller")
public class IndexController{
public void defaultAction(){
...
}
}Defining the path of action
URI mapping:
Controller/Action |
URI |
View |
|---|---|---|
| IndexController |
/mycontroller |
/WEB-INF/index/index.jsp |
| IndexController.defaultAction() |
/mycontroller/myaction |
/WEB-INF/index/defaultaction/index.jsp |
Controller
@Controller("/mycontroller")
public class IndexController{
@Action("/myaction")
public void defaultAction(){
...
}
}Defining the action strategy
URI mapping:
Controller/Action |
URI |
View |
|---|---|---|
| IndexController |
/Index |
/WEB-INF/index/index.jsp |
| IndexController.defaultAction() |
/Index/default |
/WEB-INF/index/defaultaction/index.jsp |
Controller
@ActionStrategy(ActionStrategyType.Hierarchy)
public class IndexController{
public void defaultAction(){
}
}The action strategy Detached
URI mapping:
Controller/Action |
URI |
View |
|---|---|---|
| IndexController |
| - |
| - |
| IndexController.defaultAction() |
/default |
/WEB-INF/index/defaultaction/index.jsp |
Controller
@ActionStrategy(ActionStrategyType.Detached)
public class IndexController{
@Action("/default")
public void defaultAction(){
...
}
}The action strategy Hierarchy
URI mapping:
Controller/Action |
URI |
View |
|---|---|---|
| IndexController |
/Index |
/WEB-INF/index/index.jsp |
| IndexController.defaultAction() |
/Index/default |
/WEB-INF/index/defaultaction/index.jsp |
Controller
@ActionStrategy(ActionStrategyType.Hierarchy)
public class IndexController{
public void defaultAction(){
...
}
}The action strategy Parameter
URI mapping:
Controller/Action |
URI |
View |
|---|---|---|
| IndexController |
/Index |
/WEB-INF/index/index.jsp |
| IndexController.defaultAction() |
/Index?invoke=default |
/WEB-INF/index/defaultaction/index.jsp |
Controller
@ActionStrategy(ActionStrategyType.Parameter)
public class IndexController{
public void defaultAction(){
...
}
}Defining the default action
URI mapping:
Controller/Action |
URI |
View |
|---|---|---|
| IndexController.defaultAction() |
/Index |
/WEB-INF/index/index.jsp |
| IndexController.defaultAction() |
/Index/default |
/WEB-INF/index/defaultaction/index.jsp |
Controller
@Controller(defaultActionName="/default")
public class IndexController{
public void defaultAction(){
...
}
}Defining the abstract action
URI mapping:
Controller/Action |
URI |
View |
|---|---|---|
| IndexController |
/Index |
/WEB-INF/index/index.jsp |
| IndexController |
/Index/abstractAction |
/WEB-INF/index/view.jsp |
| IndexController.defaultAction() |
/Index/default |
/WEB-INF/index/defaultaction/index.jsp |
Controller
@Action(value="/abstractAction", view=@View("view"))
public class IndexController{
public void defaultAction(){
}
}Using URI template
URI mapping:
Controller/Action |
URI |
View |
|---|---|---|
| IndexController |
/mycontroller/{user} |
/WEB-INF/index/index.jsp |
| IndexController.defaultAction() |
/mycontroller/{user}/default |
/WEB-INF/index/defaultaction/index.jsp |
Controller
@Controller("/mycontroller/{user}")
public class IndexController{
private String user;
public void defaultAction(){
...
}
}File upload
Form
<form method="POST" enctype="multipart/form-data" action="/Index/default">
<input type="file" name="image"/>
</form>Controller
public class IndexController{
public void defaultAction(@Identify(bean="image") File image){
//the parameter image is a temporary file
...
}
}File download
Controller
public class IndexController{
public File downloadAction(){
return new File("/path/file.ext");
}
}Mounting the result action
Controller
public class IndexController{
public ResultAction action1Action(ResultAction result){
result.addInfo("Content-Type", "text/html; charset=utf-8")
.setContentType(String.class)
.setContent("<html><body>test</body></html>");
return result;
}
public ResultAction action2Action (ResultAction result){
result.addInfo("Content-Type", "text/html; charset=utf-8")
.setView("myView")
.add("value1", BigDecimal.ONE);
return result;
}
}Creating a simple interceptor
Interceptor
public class MyInterceptorController implements InterceptorController{
private Map props;
public void setProperties( Map props ){
this.props = props;
}
public boolean isConfigured(){
return this.props != null;
}
public void intercepted( InterceptorStack stack, InterceptorHandler handler ) throws
InterceptedException{
//code before action
stack.next(handler);
//code after action
}
public boolean accept(InterceptorHandler handler){
return true;
}
}Controller
@InterceptedBy(@Intercept(interceptor=MyInterceptorController.class))
public class IndexController{
...
}Creating a simple interceptor stack
Interceptor A
@InterceptsStack(name="stackA")
public class MyInterceptorAInterceptorController implements InterceptorController{
...
}Interceptor B
@InterceptsStack(name="stackA", executeAfter=MyInterceptorAInterceptorController.class)
public class MyInterceptorBInterceptorController implements InterceptorController{
...
}Controller
@InterceptedBy(@Intercept(name="stackA"))
public class IndexController{
...
}Handling exceptions
URI mapping
Controller/Action |
URI |
View |
|---|---|---|
| IndexController |
/Index |
/WEB-INF/index/index.jsp |
| IndexController.defaultAction() |
/Index/default |
/WEB-INF/index/defaultaction/index.jsp |
| throw NullPointerException |
/Index/default |
/WEB-INF/index/defaultaction/nullpointerexception.jsp |
Controller
public class IndexController{
public void defaultAction() throw NullPointerException{
...
}
}Specifying handling exception
- Controller
URI mapping
Controller/Action |
URI |
View |
|---|---|---|
| IndexController |
/Index |
/WEB-INF/index/index.jsp |
| IndexController.defaultAction() |
/Index/default |
/WEB-INF/index/defaultaction/index.jsp |
| throw NullPointerException |
/Index/default |
/WEB-INF/index/defaultaction/npe.jsp |
Controller
@ThrowSafe(target=NullPointerException.class, view="npe")
public class IndexController{
public void defaultAction() throw NullPointerException{
...
}
}- Action
URI mapping
Controller/Action |
URI |
View |
|---|---|---|
| IndexController |
/Index |
/WEB-INF/index/index.jsp |
| IndexController.defaultAction() |
/Index/default |
/WEB-INF/index/defaultaction/index.jsp |
| throw NullPointerException |
/Index/default |
/WEB-INF/index/defaultaction/npe.jsp |
Controller
public class IndexController{
@ThrowSafe(target=NullPointerException.class, view="npe")
public void defaultAction() throw NullPointerException{
...
}
}Mapping simple bean
Form
<form method="POST" action="/Index">
<input type="hidden" name="invoke" value="default">
<input type="text" name="myBean.id">
</form>Bean
@Bean
public class MyBean{
private Integer id;
public void setId(Integer id){
this.id = id;
}
public Integer getId(){
return this.id;
}
}Controller
public class IndexController{
public void defaultAction(@Identify(bean="myBean") MyBean bean) {
...
}
}Defining scope of property
Bean
@Bean
public class MyBean{
private Integer id;
@Identify(scope=ScopeType.SESSION)
private User user;
...
}Defining the name of property
Form
<form method="post" ... >
<input type="text" name="paramName.my_id">
</form>Bean
@Bean
public class MyBean{
@Identify(bean="my_id")
private Integer id;
...
}Defining the constructor of bean
Bean
@Bean
public class MyBean{
public MyBean(){...}
@Constructor
public MyBean(Integer id){...}
}Defining the target class of mapping
Controller
public class MyController{
@Target(LinkedHashMap.class)
private Map property;
...
}Collection mapping
Form
<form method="post" action="...">
<input type="text" name="person.name">
<input type="text" name="person.address.element[0].type">
<input type="text" name="person.address.element[0].street">
<input type="text" name="person.address.element[0].city">
<input type="text" name="person.address.element[0].state">
</form>Bean
@Bean
public class Person {
private String name;
private List<Address> address;
...
}Bean
@Bean
public class Address {
private String type;
private String street;
private String city;
private String state;
...
}Collection mapping
Form
<form method="post" action="/person/save">
<input type="text" name="person.name">
<input type="file" name="person.address.key[0]">
<input type="file" name="person.address.element[0].type">
<input type="file" name="person.address.element[0].street">
<input type="file" name="person.address.element[0].city">
<input type="file" name="person.address.element[0].state">
</form>Bean
@Bean
public class Person {
private String name;
private Map<String, Address> address;
...
}Defining view of action
URI mapping
Controller/Action |
URI |
View |
|---|---|---|
| IndexController |
/Index |
/WEB-INF/index/controllerView.jsp |
| IndexController.defaultAction() |
/Index/default |
/jsp/index.jsp |
Controller
@View("controllerView")
public class IndexController{
@View(value="/jsp/index.jsp", resolved=true)
public void defaultAction(){
}
}Using Bean Validator
Action
public class IndexController{
public void defaultAction(@NotNull Integer arg1){
...
}
}Action
public class IndexController{
@NotNull
public Integer defaultAction(){
...
return result;
}
}Controller
public class IndexController{
@NotNull
private Integer value;
public void defaultAction(){
...
}
}Controller
public class IndexController{
private Integer value;
public void setValue(@NotNull Integer value){
this.value = value;
}
...
}Bean
@Bean
public class MyBean{
@NotNull
private Integer value;
...
}Bean
@Bean
public class MyBean{
private Integer value;
public void setValue(@NotNull Integer value){
this.value = value;
}
...
}Bean
@Bean
public class MyBean{
private Integer value;
public voud setValue(@NotNull Integer value){
this.value = value;
}
...
}Complex form and mixing form and session.
Form
<form method="post" action="/Person/save">
Person: <br>
<input type="hidden" name="person.id">
<input type="text" name="person.firstName">
<input type="text" name="person.lastName">
<input type="text" name="person.dateOfBirth">
<input type="radio" name="person.gender" value="MALE"> Male
<input type="radio" name="person.gender" value="FEMALE"> Female
Childs <br>
<!-- Child 1 -->
<input type="text" name="person.childs.element[0].firstName">
<input type="text" name="person.childs.element[0].lastName">
<input type="text" name="person.childs.element[0].dateOfBirth">
<input type="radio" name="person.childs.element[0].gender" value="MALE"> Male
<input type="radio" name="person.childs.element[0].gender" value="FEMALE"> Female
<!-- Child 2 -->
<input type="text" name="person.childs.element[1].firstName">
<input type="text" name="person.childs.element[1].lastName">
<input type="text" name="person.childs.element[1].dateOfBirth">
<input type="radio" name="person.childs.element[1].gender" value="MALE"> Male
<input type="radio" name="person.childs.element[1].gender" value="FEMALE"> Female
<!-- Child 3 -->
<input type="text" name="person.childs.element[2].firstName">
<input type="text" name="person.childs.element[2].lastName">
<input type="text" name="person.childs.element[2].dateOfBirth">
<input type="radio" name="person.childs.element[2].gender" value="MALE"> Male
<input type="radio" name="person.childs.element[2].gender" value="FEMALE"> Female
</form>Bean
public enunm Gender{
MALE,
FEMALE;
}Bean
@Bean
public class Person{
private Integer id;
private String firstName;
private String lastName;
private Date dateOfBirth;
//@Enumerated(EnumerationType.STRING)
private Gender gender;
private List<Person> childs;
...
}Controller
public class PersonController{
//or inject logged user here
//@Idendify(scope="session")
//private User loggerdUser;
public void saveAction(@Idendify(scope="session") User loggerdUser,
@Idendify(bean="person") Person person){
...
}
}See also
- Model–view–controller
- Inversion of control
- Web application framework
- Comparison of web application frameworks