Considering I've got an exam on Spring tomorrow, I figured you could review a small example application I whipped together as preparation (and as such, I'd prefer the emphasis to be on Spring-related concepts).
Its functionality is straightforward: you start with a list of 3 games and you can edit or view its details, both which will lead to a different page. The former will allow you to update its description while also providing validation on the field.
Any suggestions?
GameController
@Controller
@RequestMapping("/games")
public class GameController {
@Autowired
private IGameRepository gameRepository;
@Autowired
private GameValidator gameValidator;
@RequestMapping(value = "/all", method = RequestMethod.GET)
public String index(Model model){
model.addAttribute("games", gameRepository.getGames());
return "index";
}
@RequestMapping(value = "/details/{id}", method = RequestMethod.GET)
public String details(Model model, @PathVariable("id") int id){
Game game = gameRepository.getGameById(id);
model.addAttribute("currentGame", game);
return "details";
}
@RequestMapping(value = "/edit/{id}", method = RequestMethod.GET)
public String edit(Model model, @PathVariable("id") int id){
Game game = gameRepository.getGameById(id);
model.addAttribute("edit_game_form", game);
return "edit";
}
@RequestMapping(value = "/edit/{id}", method = RequestMethod.POST)
public ModelAndView update(@ModelAttribute("edit_game_form") @Valid Game game, BindingResult bindingResult, Model model){
gameRepository.updateGame(game);
gameValidator.validate(game, bindingResult);
if(bindingResult.hasErrors()){
return new ModelAndView("edit", "edit_game_form", game);
}
model.addAttribute("games", gameRepository.getGames());
return new ModelAndView("index");
}
}
Game
public class Game {
private int id;
private String title;
private String description;
public Game(){ }
public Game(int id, String title, String description) {
this.id = id;
this.title = title;
this.description = description;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}
GameRepository
public class GameRepository implements IGameRepository{
private List<Game> games = new ArrayList<>();
public GameRepository(){
games.add(new Game(1, "League of Legends", "fun game"));
games.add(new Game(5, "Call of Duty 4", "awesome game"));
games.add(new Game(4, "Farmville", "gtfo"));
}
@Override
public List<Game> getGames() {
return games;
}
@Override
public Game getGameById(int id) {
for(Game game : games){
if(game.getId() == id){
return game;
}
}
throw new IllegalArgumentException("This id is not found");
}
@Override
public void updateGame(Game game) {
Iterator<Game> it = games.iterator();
while(it.hasNext()){
Game currentGame = it.next();
if(currentGame.getId() == game.getId()){
it.remove();
break;
}
}
games.add(game);
}
}
IGameRepository
public interface IGameRepository {
public List<Game> getGames();
public Game getGameById(int id);
public void updateGame(Game game);
}
GameValidator
public class GameValidator implements Validator {
@Override
public boolean supports(Class<?> type) {
return type == Game.class;
}
/* Arbitrary restrictions on the description:
- Between 5 and 25 characters
- Cannot contain a number
*/
@Override
public void validate(Object o, Errors errors) {
Game game = (Game) o;
String description = game.getDescription();
if(description.length() < 5 || description.length() > 25){
errors.rejectValue("description", "TODO:localization", "Stay within the boundaries");
}
if(description.matches(".*\\d.*")){
errors.rejectValue("description", "TODO:localization", "NO NUMBERS!");
}
}
}
ApplicationContext
<bean id="gameRepository" class="domain.GameRepository" />
<bean id="gameValidator" class="domain.GameValidator" />
Index.jsp
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Overview</title>
</head>
<spring:url value="/games/details/" var="detailsUrl" />
<spring:url value="/games/edit/" var="editUrl" />
<body>
<h2>Games</h2>
<table>
<thead>
<th> Id </th>
<th> Title </th>
<th> Description </th>
</thead>
<tbody>
<c:forEach items="${games}" var="game" varStatus="status">
<tr>
<td>${game.id}</td>
<td>${game.title}</td>
<td>${game.description}</td>
<td><a href="${detailsUrl}${game.id}.htm">Details</a></td>
<td><a href="${editUrl}${game.id}.htm">Edit</a></td>
</tr>
</c:forEach>
</tbody>
</table>
</body>
</html>
Details.jsp
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Details - ${currentGame.title}</title>
</head>
<body>
<h1> Details for ${currentGame.title} </h1>
<p>
Description: ${currentGame.description}
</p>
</body>
</html>
Edit.jsp
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Edit - ${currentGame.title}</title>
</head>
<body>
<style>
.error { color: red; }
</style>
<h1>Update game information</h1>
<form:form method="POST" modelAttribute="edit_game_form">
<form:errors path="*" cssClass="error" element="div"/>
<form:hidden path="title" />
<table>
<tr>
<td>
Description:
</td>
<td>
<form:input path="description" />
</td>
<td>
<form:errors path="description" cssClass="error" />
</td>
</tr>
<tr>
<td colspan="3">
<input type="submit" value="Update" />
</td>
</tr>
</table>
</form:form>
</body>
</html>