Welcome to MVC Framework, a lightweight server-side web framework inspired by Spring Web. This framework supports MVC architecture with dynamic view rendering and provides built-in support for controllers, routing, path variables, query parameters, and multiple HTTP verbs.
Annotate your main application class with @WebApplication to mark it as the starting point:
@WebApplication("be.kdg.prog3")
public class Main {
public static void main(String[] args) {
Application.run(Main.class);
}
}Here:
"be.kdg.prog3"is the base package where the framework will scan for controllers.
Controllers are annotated with @MvcController and can define route methods with @Get, @Post, etc.
@MvcController
@ControllerPath("/movies")
public class MovieController {
@Get
public ModelView getMovies() {
ModelView modelView = new ModelView();
modelView.setViewName("movies");
List<Movie> movies = MovieService.getAllMovies();
modelView.addObject("movies", movies);
modelView.addObject("isAdmin", true);
return modelView;
}
@Post("/add")
public ModelView AddMovie(@QueryVariable("title") String title, @QueryVariable("director") String director, @QueryVariable("year") int year) {
Movie movie = MovieService.addMovie(title, director, year);
ModelView modelView = new ModelView();
modelView.setViewName("detail");
modelView.addObject("title", movie.getTitle());
modelView.addObject("director", movie.getDirector());
modelView.addObject("year", movie.getYear());
return modelView;
}
}Example:
GET http://localhost:8080/movies/1
@Get("/{id}")
public ModelView getMovieById(@PathVariable("id") int movieId) {
ModelView modelView = new ModelView();
modelView.setViewName("detail");
Movie movie = MovieService.getMovieById(movieId);
modelView.addObject("title", movie.getTitle());
modelView.addObject("director", movie.getDirector());
modelView.addObject("year", movie.getYear());
return modelView;
}Returning View:
<html>
<h1>The Shawshank Redemption</h1>
<table>
<tr>
<th>Director</th>
<td>Frank Darabont</td>
</tr>
<tr>
<th>Year</th>
<td>1994</td>
</tr>
</table>
</html>This framework uses a custom XML-based template language defined with ANTLR. These view files should be placed in the folder views inside a resource directory
- Variable:
${variableName} - If:
<if condition="\${conditionVar}"> ... </if> - For loop:
<for var="item" items="\${listVar}"> ... </for> - Plain HTML tags:
<html>,<div>,<p>,<span>,<h1>… (see grammar below) - Input tag:
<input type="text" name="fieldName"/>
/views/movies.xml
<html>
<h1>Movie overview</h1>
<a href="/">Return to home page</a>
<a href="/movies/watchlist">Watchlist</a>
<form action="/movies/name" method="GET">
<input type="text" name="name" placeholder="Search movie by name"/>
<button type="submit">Search</button>
</form>
<ul>
<for var="movie" items="${movies}">
<li><a href="/movies/${movie.id}">${movie}</a></li>
</for>
</ul>
<if condition="${isAdmin}">
<button onclick="location.href= '/movies/form'">Add movie</button>
</if>
</html>Variables:
- Movies: Inception, Goodfellas, The Matrix
- isAdmin: true
<html>
<h1>Movie overview</h1>
<a href="/">Return to home page</a>
<a href="/movies/watchlist">Watchlist</a>
<form action="/movies/name" method="GET">
<input type="text" name="name" placeholder="Search movie by name"/>
<button type="submit">Search</button>
</form>
<ul>
<li>
<a href="/movies/1">Inception</a>
</li>
<li>
<a href="/movies/2">Goodfellas</a>
</li>
<li>
<a href="/movies/3">The Matrix</a>
</li>
</ul>
<button onclick="location.href= '/movies/form'">Add movie</button>
</html>This framework supports custom error pages for HTTP status codes such as 404 Not Found, 500 Internal Server Error, etc.
The ViewHandler will:
- Look for a corresponding XML template in
/views/errors/<statusCode>.xml. - If the template exists, it will render it as the error page.
- If it does not exist, it will fall back to a default minimal HTML error page.
Example file: /resources/views/errors/404.xml
<html>
<h1>Page Not Found</h1>
<p>The page you are looking for does not exist.</p>
<a href="/">Return Home</a>
</html>grammar ViewTemplate;
view
: element+ EOF
;
element
: tag
| VARIABLE
| TEXT
;
tag
: ifTag
| forTag
| inputTag
| plainTag
;
ifTag
: OPEN_IF_TAG element* CLOSE_IF_TAG WS*
;
forTag
: OPEN_FOR_TAG element* CLOSE_FOR_TAG WS*
;
inputTag
: OPEN_INPUT WS*
;
plainTag
: OPEN_PLAIN_TAG element* CLOSE_PLAIN_TAG WS*
;
OPEN_IF_TAG
: '<if condition="' VARIABLE '">'
;
CLOSE_IF_TAG
: '</if>'
;
OPEN_FOR_TAG
: '<for var="' ID '" items="' VARIABLE '">'
;
CLOSE_FOR_TAG
: '</for>'
;
OPEN_INPUT
: '<input' ATTRIBUTE* '/>'
;
OPEN_PLAIN_TAG
: '<' KEYWORD ATTRIBUTE* '>'
;
CLOSE_PLAIN_TAG
: '</' KEYWORD '>'
;
ATTRIBUTE
: TEXT '=' STRING
;
VARIABLE
: '${' ID '}'
;
TEXT
: ~[<${}]+
;
ID
: [a-zA-Z_][a-zA-Z0-9_.()]*
;
STRING
: '"' (~["])* '"'
;
KEYWORD
: 'html'
| 'div'
| 'p'
| 'span'
| 'h1'
| 'h2'
| 'h3'
| 'ul'
| 'ol'
| 'li'
| 'a'
| 'button'
| 'table'
| 'tr'
| 'th'
| 'td'
| 'form'
;
WS
: [ \t\r\n]+ -> skip
;
- Entry point for running your app.
- Validates
@WebApplicationannotation. - Scans for controllers and registers them.
- Uses Reflections to find classes annotated with
@MvcController.
- Holds:
- Controller instances
- Mappings of HTTP method + path → controller method
- Regex route matching for
{variables}
- Minimal raw socket HTTP listener (no servlet container).
- Parses request lines, headers, query parameters, and body.
- Handles
/shutdowncommand for stopping the server.
- Finds matching route in
ControllerRegistry. - Extracts parameters using
ArgumentHandler. - Invokes controller method & returns
HttpResponse.
- Maps
@PathVariableand@QueryVariablevalues to method parameters. - Performs type conversion (
String,int,long,double,boolean).
- Loads view templates from resources.
- Returns error pages for missing templates.
- Parses templates with ANTLR grammar.
- Supports:
- Variable interpolation
ifconditionsforloops- Tag rendering