├── LICENSE ├── README.md ├── WorkInProgress.md ├── pom.xml ├── src └── main │ ├── java │ └── com │ │ └── in28minutes │ │ ├── model │ │ └── Todo.java │ │ ├── struts │ │ ├── EditAddTodoAction.java │ │ ├── ListTodosAction.java │ │ ├── ShowTodoAction.java │ │ └── WelcomeAction.java │ │ └── todo │ │ └── service │ │ └── TodoService.java │ ├── resources │ ├── log4j.properties │ ├── messages_en.properties │ ├── messages_fr.properties │ └── struts.xml │ └── webapp │ └── WEB-INF │ ├── views │ ├── common │ │ ├── footer.jspf │ │ ├── header.jspf │ │ └── navigation.jspf │ ├── error.jsp │ └── user │ │ ├── customized-error.jsp │ │ ├── list-todos.jsp │ │ ├── todo.jsp │ │ └── welcome.jsp │ └── web.xml └── workInProgress.zip /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Struts Tutorial For Beginners 2 | Struts Tutorial For Beginners in 25 Easy Steps 3 | 4 | # Todo 5 | - Delete todo 6 | - Rest Service 7 | - Internationalization 8 | - Spring Security (remove hardcoding of userName) 9 | - JSR Validation.The JSR 303 and JSR 349 defines specification for the Bean Validation API (version 1.0 and 1.1, respectively), and Hibernate Validator is the reference implementation. 10 | 11 | # First Struts 2 Application in 25 Easy Steps 12 | 13 | ## Struts 2 Tutorial for Beginners 14 | 15 | ## Installing Eclipse and Java 16 | https://github.com/in28minutes/SpringIn28Minutes/blob/master/InstallationGuide-JavaEclipseAndMaven_v2.pdf 17 | 18 | ## Course Overview 19 | 20 | ### Steps 1 to 7 : Build a normal Web Application 21 | - Understand Basics of HTTP - HttpRequest - GET/POST, Request Parameters 22 | - Introduction to JSP, Servlets, JSTL, Scriptlets and EL. 23 | - Understand Basics of using Maven, Tomcat and Eclipse 24 | 25 | ### Steps 11 to XX : Use Struts 2 to Build Your First Web Application 26 | - struts-default, Interceptors, @Action, @Namespace 27 | - Forms - DataBinding, Validation 28 | - Annotation based approach 29 | - Bootstrap to style the page 30 | - Spring Security 31 | - Internationalization - Validation Messages 32 | - Exception Handling 33 | - Basic REST Services 34 | - Logout 35 | 36 | ## Our Approach 37 | - Instead of taking traditional approach, feature-by-feature, we will take a problem-solution step-by-step approach. 38 | - We will use 80-20 Rule. We discuss the 20% things used 80% of time in depth. We touch upon other things briefly equipping you with enough knowledge to find out more on your own. 39 | - We will be developing a demo application in the course, which could be reused in your projects, saving hours of your effort. 40 | - All the code is available on Github, step by step. 41 | - We will use Struts 2.3 42 | 43 | ## Expectations 44 | - For taking this course, you should already know Java. 45 | - We expect NO prior experience with web development using Java. 46 | - We expect NO prior experience with Struts or Spring Security. 47 | 48 | ## Step wise details 49 | - Step01.md : Up and running with a web app in Tomcat 50 | - Step02.md : First JSP 51 | - Step03.md : Adding a GET Parameter name 52 | - Step04.md : Adding another Get Parameter Password 53 | - Step05.md : Lets add a form 54 | - Step06.md : New Form and doPost 55 | - Step07.md : Adding Password, validation of userid/password 56 | ... 57 | ... 58 | ... 59 | ... 60 | 61 | ## Exercises 62 | - Functionality to mark a Todo as complete 63 | 64 | ## Future Things To Do 65 | - Unit Tests - WTF - why are they not here in the first set? 66 | 67 | ### Other Courses 68 | 69 | - [Check out all our courses with 100,000 Students](https://courses.in28minutes.com/courses) 70 | - [25 Videos and Articles for Beginners on Spring Boot](http://www.springboottutorial.com/spring-boot-tutorials-for-beginners) 71 | - Our Best Courses with 66,000 Students and 4,000 5-Star Ratings 72 | * [Java Interview Guide : 200+ Interview Questions and Answers](https://www.udemy.com/java-interview-questions-and-answers/?couponCode=JAVA_INTER_GIT) 73 | * [First Web Application with Spring Boot](https://www.udemy.com/spring-boot-first-web-application/?couponCode=SPRING-BOOT-1-GIT) 74 | * [Spring Boot Tutorial For Beginners](https://www.udemy.com/spring-boot-tutorial-for-beginners/?couponCode=SPRING-BOOT-GIT) 75 | * [Mockito Tutorial : Learn mocking with 25 Junit Examples](https://www.udemy.com/mockito-tutorial-with-junit-examples/?couponCode=MOCKITO_GIT) 76 | * [Java EE Made Easy - Patterns, Architecture and Frameworks](https://www.udemy.com/java-ee-design-patterns-architecture-and-frameworks/?couponCode=EEPATTERNS-GIT) 77 | * [Spring MVC For Beginners : Build Java Web App in 25 Steps](https://www.udemy.com/spring-mvc-tutorial-for-beginners-step-by-step/?couponCode=SPRINGMVC-GIT) 78 | * [JSP Servlets For Beginners : Build Java Web App in 25 Steps](https://www.udemy.com/learn-java-servlets-and-jsp-web-application-in-25-steps/?couponCode=JSPSRVLT-GIT) 79 | * [Maven Tutorial - Manage Java Dependencies in 25 Steps](https://www.udemy.com/learn-maven-java-dependency-management-in-20-steps/?couponCode=MAVEN_GIT) 80 | * [Java OOPS in 1 Hours](https://www.udemy.com/learn-object-oriented-programming-in-java/?couponCode=OOPS-GIT) 81 | * [C Puzzle for Interview](https://www.udemy.com/c-puzzles-for-beginners/?couponCode=CPUZZLES-GIT) 82 | 83 | ### Useful Links 84 | - [Our Website](http://www.in28minutes.com) 85 | - [Facebook](http://facebook.com/in28minutes) 86 | - [Twitter](http://twitter.com/in28minutes) 87 | - [Google Plus](https://plus.google.com/u/3/110861829188024231119) 88 | -------------------------------------------------------------------------------- /WorkInProgress.md: -------------------------------------------------------------------------------- 1 | ## Files List 2 | ### pom.xml 3 | ``` 4 | 6 | 4.0.0 7 | com.in28minutes 8 | in28Minutes-struts 9 | 0.0.1-SNAPSHOT 10 | war 11 | 12 | 13 | 14 | javax 15 | javaee-web-api 16 | 6.0 17 | provided 18 | 19 | 20 | 21 | org.apache.struts 22 | struts2-core 23 | 2.3.24.1 24 | 25 | 26 | 27 | 28 | org.apache.struts 29 | struts2-convention-plugin 30 | 2.3.24.1 31 | 32 | 33 | 34 | javax.servlet 35 | jstl 36 | 1.2 37 | 38 | 39 | 40 | org.webjars 41 | bootstrap 42 | 3.3.6 43 | 44 | 45 | org.webjars 46 | jquery 47 | 1.9.1 48 | 49 | 50 | 51 | org.webjars 52 | bootstrap-datepicker 53 | 1.0.1 54 | 55 | 56 | 57 | org.hibernate 58 | hibernate-validator 59 | 5.0.2.Final 60 | 61 | 62 | 63 | log4j 64 | log4j 65 | 1.2.17 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | org.apache.maven.plugins 74 | maven-compiler-plugin 75 | 3.2 76 | 77 | true 78 | 1.8 79 | 1.8 80 | true 81 | 82 | 83 | 84 | org.apache.tomcat.maven 85 | tomcat7-maven-plugin 86 | 2.2 87 | 88 | / 89 | true 90 | 91 | 92 | 93 | 94 | 95 | 96 | ``` 97 | ### src/main/java/com/in28minutes/model/Todo.java 98 | ``` 99 | package com.in28minutes.model; 100 | 101 | import java.util.Date; 102 | 103 | import javax.validation.constraints.Size; 104 | 105 | public class Todo { 106 | private int id; 107 | 108 | private String user; 109 | 110 | @Size(min = 10, message = "Enter atleast 10 Characters.") 111 | private String desc; 112 | 113 | private Date targetDate; 114 | private boolean isDone; 115 | 116 | public Todo() { 117 | super(); 118 | } 119 | 120 | public Todo(int id, String user, String desc, Date targetDate, 121 | boolean isDone) { 122 | super(); 123 | this.id = id; 124 | this.user = user; 125 | this.desc = desc; 126 | this.targetDate = targetDate; 127 | this.isDone = isDone; 128 | } 129 | 130 | public int getId() { 131 | return id; 132 | } 133 | 134 | public void setId(int id) { 135 | this.id = id; 136 | } 137 | 138 | public String getUser() { 139 | return user; 140 | } 141 | 142 | public void setUser(String user) { 143 | this.user = user; 144 | } 145 | 146 | public String getDesc() { 147 | return desc; 148 | } 149 | 150 | public void setDesc(String desc) { 151 | this.desc = desc; 152 | } 153 | 154 | public Date getTargetDate() { 155 | return targetDate; 156 | } 157 | 158 | public void setTargetDate(Date targetDate) { 159 | this.targetDate = targetDate; 160 | } 161 | 162 | public boolean isDone() { 163 | return isDone; 164 | } 165 | 166 | public void setDone(boolean isDone) { 167 | this.isDone = isDone; 168 | } 169 | 170 | @Override 171 | public int hashCode() { 172 | final int prime = 31; 173 | int result = 1; 174 | result = prime * result + id; 175 | return result; 176 | } 177 | 178 | @Override 179 | public boolean equals(Object obj) { 180 | if (this == obj) 181 | return true; 182 | if (obj == null) 183 | return false; 184 | if (getClass() != obj.getClass()) 185 | return false; 186 | Todo other = (Todo) obj; 187 | if (id != other.id) 188 | return false; 189 | return true; 190 | } 191 | 192 | @Override 193 | public String toString() { 194 | return String.format( 195 | "Todo [id=%s, user=%s, desc=%s, targetDate=%s, isDone=%s]", id, 196 | user, desc, targetDate, isDone); 197 | } 198 | 199 | } 200 | ``` 201 | ### src/main/java/com/in28minutes/struts/EditAddTodoAction.java 202 | ``` 203 | package com.in28minutes.struts; 204 | 205 | import org.apache.struts2.convention.annotation.Action; 206 | import org.apache.struts2.convention.annotation.Namespace; 207 | import org.apache.struts2.convention.annotation.Result; 208 | import org.apache.struts2.convention.annotation.ResultPath; 209 | 210 | import com.in28minutes.model.Todo; 211 | import com.in28minutes.todo.service.TodoService; 212 | 213 | @Namespace("/user") 214 | @ResultPath(value = "/WEB-INF/views/") 215 | public class EditAddTodoAction { 216 | private Todo todo; 217 | 218 | @Action(value = "edit-todo", results = { @Result(name = "success", type = "redirect", location = "list-todos") }) 219 | public String execute() { 220 | TodoService todoService = new TodoService(); 221 | if (todo.getId() > 0) { 222 | todo.setUser("in28Minutes"); 223 | todoService.updateTodo(todo); 224 | } else { 225 | todoService.addTodo("in28Minutes", todo.getDesc(), 226 | todo.getTargetDate(), false); 227 | 228 | } 229 | return "success"; 230 | } 231 | 232 | public Todo getTodo() { 233 | return todo; 234 | } 235 | 236 | public void setTodo(Todo todo) { 237 | this.todo = todo; 238 | } 239 | } 240 | ``` 241 | ### src/main/java/com/in28minutes/struts/ListTodosAction.java 242 | ``` 243 | package com.in28minutes.struts; 244 | 245 | import java.util.ArrayList; 246 | import java.util.List; 247 | 248 | import org.apache.struts2.convention.annotation.Action; 249 | import org.apache.struts2.convention.annotation.ExceptionMapping; 250 | import org.apache.struts2.convention.annotation.ExceptionMappings; 251 | import org.apache.struts2.convention.annotation.Namespace; 252 | import org.apache.struts2.convention.annotation.Result; 253 | import org.apache.struts2.convention.annotation.ResultPath; 254 | 255 | import com.in28minutes.model.Todo; 256 | import com.in28minutes.todo.service.TodoService; 257 | 258 | @Namespace("/user") 259 | @ResultPath(value = "/WEB-INF/views/") 260 | @ExceptionMappings({ @ExceptionMapping(exception = "java.lang.Exception", result = "error") }) 261 | public class ListTodosAction { 262 | private List todos = new ArrayList(); 263 | 264 | public List getTodos() { 265 | return todos; 266 | } 267 | 268 | @Action(value = "list-todos", results = { 269 | @Result(name = "success", location = "list-todos.jsp"), 270 | @Result(name = "error", location = "customized-error.jsp") }) 271 | public String execute() { 272 | todos = new TodoService().retrieveTodos("in28Minutes"); 273 | return "success"; 274 | } 275 | } 276 | ``` 277 | ### src/main/java/com/in28minutes/struts/ShowTodoAction.java 278 | ``` 279 | package com.in28minutes.struts; 280 | 281 | import java.util.Date; 282 | 283 | import org.apache.struts2.convention.annotation.Action; 284 | import org.apache.struts2.convention.annotation.Namespace; 285 | import org.apache.struts2.convention.annotation.Result; 286 | import org.apache.struts2.convention.annotation.ResultPath; 287 | 288 | import com.in28minutes.model.Todo; 289 | import com.in28minutes.todo.service.TodoService; 290 | 291 | @Namespace("/user") 292 | @ResultPath(value = "/WEB-INF/views/") 293 | public class ShowTodoAction { 294 | private int id = 0; 295 | 296 | private Todo todo = new Todo(0, "in28Minutes", "Learn Spring MVC", 297 | new Date(), false); 298 | 299 | @Action(value = "show-todo", results = { @Result(name = "success", location = "todo.jsp") }) 300 | public String execute() { 301 | if (id > 0) { 302 | todo = new TodoService().retrieveTodo(id); 303 | } 304 | return "success"; 305 | } 306 | 307 | public Todo getTodo() { 308 | return todo; 309 | } 310 | 311 | public int getId() { 312 | return id; 313 | } 314 | 315 | public void setId(int id) { 316 | this.id = id; 317 | } 318 | } 319 | ``` 320 | ### src/main/java/com/in28minutes/struts/WelcomeAction.java 321 | ``` 322 | package com.in28minutes.struts; 323 | 324 | import org.apache.struts2.convention.annotation.Action; 325 | import org.apache.struts2.convention.annotation.Namespace; 326 | import org.apache.struts2.convention.annotation.Result; 327 | import org.apache.struts2.convention.annotation.ResultPath; 328 | 329 | @Namespace("/user") 330 | @ResultPath(value = "/WEB-INF/views/") 331 | public class WelcomeAction { 332 | @Action(value = "welcome", results = { @Result(name = "success", location = "welcome.jsp") }) 333 | public String execute() { 334 | return "success"; 335 | } 336 | } 337 | ``` 338 | ### src/main/java/com/in28minutes/todo/service/TodoService.java 339 | ``` 340 | package com.in28minutes.todo.service; 341 | 342 | import java.util.ArrayList; 343 | import java.util.Date; 344 | import java.util.Iterator; 345 | import java.util.List; 346 | 347 | import com.in28minutes.model.Todo; 348 | 349 | public class TodoService { 350 | private static List todos = new ArrayList(); 351 | private static int todoCount = 3; 352 | 353 | static { 354 | todos.add(new Todo(1, "in28Minutes", "Learn Spring MVC", new Date(), 355 | false)); 356 | todos.add(new Todo(2, "in28Minutes", "Learn Struts", new Date(), false)); 357 | todos.add(new Todo(3, "in28Minutes", "Learn Hibernate", new Date(), 358 | false)); 359 | } 360 | 361 | public List retrieveTodos(String user) { 362 | List filteredTodos = new ArrayList(); 363 | for (Todo todo : todos) { 364 | if (todo.getUser().equals(user)) 365 | filteredTodos.add(todo); 366 | } 367 | return filteredTodos; 368 | } 369 | 370 | public Todo retrieveTodo(int id) { 371 | for (Todo todo : todos) { 372 | if (todo.getId() == id) 373 | return todo; 374 | } 375 | return null; 376 | } 377 | 378 | public void updateTodo(Todo todo) { 379 | todos.remove(todo); 380 | todos.add(todo); 381 | } 382 | 383 | public void addTodo(String name, String desc, Date targetDate, 384 | boolean isDone) { 385 | todos.add(new Todo(++todoCount, name, desc, targetDate, isDone)); 386 | } 387 | 388 | public void deleteTodo(int id) { 389 | Iterator iterator = todos.iterator(); 390 | while (iterator.hasNext()) { 391 | Todo todo = iterator.next(); 392 | if (todo.getId() == id) { 393 | iterator.remove(); 394 | } 395 | } 396 | } 397 | } 398 | ``` 399 | ### src/main/resources/log4j.properties 400 | ``` 401 | log4j.rootLogger=DEBUG, Appender1 402 | 403 | log4j.appender.Appender1=org.apache.log4j.ConsoleAppender 404 | log4j.appender.Appender1.layout=org.apache.log4j.PatternLayout 405 | log4j.appender.Appender1.layout.ConversionPattern=%-7p %d [%t] %c %x - %m%n 406 | 407 | ``` 408 | ### src/main/resources/messages_en.properties 409 | ``` 410 | welcome.message=Welcome in English 411 | todo.caption= Todo Caption in English 412 | ``` 413 | ### src/main/resources/messages_fr.properties 414 | ``` 415 | welcome.message=Welcome in French 416 | todo.caption= Todo Caption in French 417 | ``` 418 | ### src/main/resources/struts.xml 419 | ``` 420 | 421 | 422 | 425 | 426 | 427 | 428 | /Error.jsp 429 | 430 | 431 | 432 | 434 | 435 | 436 | 437 | 438 | ``` 439 | ### src/main/webapp/WEB-INF/views/common/footer.jspf 440 | ``` 441 | 442 | 443 | 444 | 446 | 447 | 448 | 449 | ``` 450 | ### src/main/webapp/WEB-INF/views/common/header.jspf 451 | ``` 452 | <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> 453 | <%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%> 454 | <%@ taglib prefix="s" uri="/struts-tags"%> 455 | 456 | 457 | Todos Application 458 | 460 | 469 | 470 | 471 | 472 | 473 | ``` 474 | ### src/main/webapp/WEB-INF/views/common/navigation.jspf 475 | ``` 476 | 492 | ``` 493 | ### src/main/webapp/WEB-INF/views/error.jsp 494 | ``` 495 | <%@ include file="common/header.jspf"%> 496 | <%@ include file="common/navigation.jspf"%> 497 |
498 | Application has encountered an error. Please contact support on ... 499 |
500 | 501 | <%@ include file="common/footer.jspf"%> 502 | ``` 503 | ### src/main/webapp/WEB-INF/views/user/customized-error.jsp 504 | ``` 505 | <%@ include file="../common/header.jspf"%> 506 | <%@ include file="../common/navigation.jspf"%> 507 |
Application has encountered an error.
508 |
Exception name: ${exception}
509 |
Exception stack trace: ${exceptionStack}
510 | 511 | <%@ include file="../common/footer.jspf"%> 512 | ``` 513 | ### src/main/webapp/WEB-INF/views/user/list-todos.jsp 514 | ``` 515 | <%@ include file="../common/header.jspf"%> 516 | <%@ include file="../common/navigation.jspf"%> 517 | 518 |
519 | 520 | 521 | 522 | 523 | 524 | 525 | 526 | 527 | 528 | 529 | 530 | 531 | 532 | 533 | 535 | 536 | 540 | 541 | 542 | 543 |
TODO Caption
DescriptionDateCompleted
${todo.desc}${todo.done}Edit Delete 539 |
544 |
545 | Add 546 |
547 |
548 | <%@ include file="../common/footer.jspf"%> 549 | ``` 550 | ### src/main/webapp/WEB-INF/views/user/todo.jsp 551 | ``` 552 | <%@ include file="../common/header.jspf"%> 553 | <%@ include file="../common/navigation.jspf"%> 554 |
555 | 556 | 557 | 558 | 559 | 560 | 561 | 562 | 563 | 564 | 565 | 566 | 567 |
568 | 569 | <%@ include file="../common/footer.jspf"%> 570 | 571 | 576 | ``` 577 | ### src/main/webapp/WEB-INF/views/user/welcome.jsp 578 | ``` 579 | <%@ include file="../common/header.jspf"%> 580 | <%@ include file="../common/navigation.jspf"%> 581 |
582 | Welcome 583 |
584 | 585 | <%@ include file="../common/footer.jspf"%> 586 | ``` 587 | ### src/main/webapp/WEB-INF/web.xml 588 | ``` 589 | 592 | 593 | To do List 594 | 595 | 596 | struts2 597 | org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter 598 | 599 | 600 | 601 | struts2 602 | /* 603 | 604 | 605 | 606 | /WEB-INF/views/error.jsp 607 | 608 | 609 | ``` 610 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | com.in28minutes 5 | in28Minutes-struts 6 | 0.0.1-SNAPSHOT 7 | war 8 | 9 | 10 | 11 | javax 12 | javaee-web-api 13 | 6.0 14 | provided 15 | 16 | 17 | 18 | org.apache.struts 19 | struts2-core 20 | 2.3.24.1 21 | 22 | 23 | 24 | 25 | org.apache.struts 26 | struts2-convention-plugin 27 | 2.3.24.1 28 | 29 | 30 | 31 | javax.servlet 32 | jstl 33 | 1.2 34 | 35 | 36 | 37 | org.webjars 38 | bootstrap 39 | 3.3.6 40 | 41 | 42 | org.webjars 43 | jquery 44 | 1.9.1 45 | 46 | 47 | 48 | org.webjars 49 | bootstrap-datepicker 50 | 1.0.1 51 | 52 | 53 | 54 | org.hibernate 55 | hibernate-validator 56 | 5.0.2.Final 57 | 58 | 59 | 60 | log4j 61 | log4j 62 | 1.2.17 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | org.apache.maven.plugins 71 | maven-compiler-plugin 72 | 3.2 73 | 74 | true 75 | 1.8 76 | 1.8 77 | true 78 | 79 | 80 | 81 | org.apache.tomcat.maven 82 | tomcat7-maven-plugin 83 | 2.2 84 | 85 | / 86 | true 87 | 88 | 89 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /src/main/java/com/in28minutes/model/Todo.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.model; 2 | 3 | import java.util.Date; 4 | 5 | import javax.validation.constraints.Size; 6 | 7 | public class Todo { 8 | private int id; 9 | 10 | private String user; 11 | 12 | @Size(min = 10, message = "Enter atleast 10 Characters.") 13 | private String desc; 14 | 15 | private Date targetDate; 16 | private boolean isDone; 17 | 18 | public Todo() { 19 | super(); 20 | } 21 | 22 | public Todo(int id, String user, String desc, Date targetDate, 23 | boolean isDone) { 24 | super(); 25 | this.id = id; 26 | this.user = user; 27 | this.desc = desc; 28 | this.targetDate = targetDate; 29 | this.isDone = isDone; 30 | } 31 | 32 | public int getId() { 33 | return id; 34 | } 35 | 36 | public void setId(int id) { 37 | this.id = id; 38 | } 39 | 40 | public String getUser() { 41 | return user; 42 | } 43 | 44 | public void setUser(String user) { 45 | this.user = user; 46 | } 47 | 48 | public String getDesc() { 49 | return desc; 50 | } 51 | 52 | public void setDesc(String desc) { 53 | this.desc = desc; 54 | } 55 | 56 | public Date getTargetDate() { 57 | return targetDate; 58 | } 59 | 60 | public void setTargetDate(Date targetDate) { 61 | this.targetDate = targetDate; 62 | } 63 | 64 | public boolean isDone() { 65 | return isDone; 66 | } 67 | 68 | public void setDone(boolean isDone) { 69 | this.isDone = isDone; 70 | } 71 | 72 | @Override 73 | public int hashCode() { 74 | final int prime = 31; 75 | int result = 1; 76 | result = prime * result + id; 77 | return result; 78 | } 79 | 80 | @Override 81 | public boolean equals(Object obj) { 82 | if (this == obj) 83 | return true; 84 | if (obj == null) 85 | return false; 86 | if (getClass() != obj.getClass()) 87 | return false; 88 | Todo other = (Todo) obj; 89 | if (id != other.id) 90 | return false; 91 | return true; 92 | } 93 | 94 | @Override 95 | public String toString() { 96 | return String.format( 97 | "Todo [id=%s, user=%s, desc=%s, targetDate=%s, isDone=%s]", id, 98 | user, desc, targetDate, isDone); 99 | } 100 | 101 | } -------------------------------------------------------------------------------- /src/main/java/com/in28minutes/struts/EditAddTodoAction.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.struts; 2 | 3 | import org.apache.struts2.convention.annotation.Action; 4 | import org.apache.struts2.convention.annotation.Namespace; 5 | import org.apache.struts2.convention.annotation.Result; 6 | import org.apache.struts2.convention.annotation.ResultPath; 7 | 8 | import com.in28minutes.model.Todo; 9 | import com.in28minutes.todo.service.TodoService; 10 | 11 | @Namespace("/user") 12 | @ResultPath(value = "/WEB-INF/views/") 13 | public class EditAddTodoAction { 14 | private Todo todo; 15 | 16 | @Action(value = "edit-todo", results = { @Result(name = "success", type = "redirect", location = "list-todos") }) 17 | public String execute() { 18 | TodoService todoService = new TodoService(); 19 | if (todo.getId() > 0) { 20 | todo.setUser("in28Minutes"); 21 | todoService.updateTodo(todo); 22 | } else { 23 | todoService.addTodo("in28Minutes", todo.getDesc(), 24 | todo.getTargetDate(), false); 25 | 26 | } 27 | return "success"; 28 | } 29 | 30 | public Todo getTodo() { 31 | return todo; 32 | } 33 | 34 | public void setTodo(Todo todo) { 35 | this.todo = todo; 36 | } 37 | } -------------------------------------------------------------------------------- /src/main/java/com/in28minutes/struts/ListTodosAction.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.struts; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import org.apache.struts2.convention.annotation.Action; 7 | import org.apache.struts2.convention.annotation.ExceptionMapping; 8 | import org.apache.struts2.convention.annotation.ExceptionMappings; 9 | import org.apache.struts2.convention.annotation.Namespace; 10 | import org.apache.struts2.convention.annotation.Result; 11 | import org.apache.struts2.convention.annotation.ResultPath; 12 | 13 | import com.in28minutes.model.Todo; 14 | import com.in28minutes.todo.service.TodoService; 15 | 16 | @Namespace("/user") 17 | @ResultPath(value = "/WEB-INF/views/") 18 | @ExceptionMappings({ @ExceptionMapping(exception = "java.lang.Exception", result = "error") }) 19 | public class ListTodosAction { 20 | private List todos = new ArrayList(); 21 | 22 | public List getTodos() { 23 | return todos; 24 | } 25 | 26 | @Action(value = "list-todos", results = { 27 | @Result(name = "success", location = "list-todos.jsp"), 28 | @Result(name = "error", location = "customized-error.jsp") }) 29 | public String execute() { 30 | todos = new TodoService().retrieveTodos("in28Minutes"); 31 | return "success"; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/in28minutes/struts/ShowTodoAction.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.struts; 2 | 3 | import java.util.Date; 4 | 5 | import org.apache.struts2.convention.annotation.Action; 6 | import org.apache.struts2.convention.annotation.Namespace; 7 | import org.apache.struts2.convention.annotation.Result; 8 | import org.apache.struts2.convention.annotation.ResultPath; 9 | 10 | import com.in28minutes.model.Todo; 11 | import com.in28minutes.todo.service.TodoService; 12 | 13 | @Namespace("/user") 14 | @ResultPath(value = "/WEB-INF/views/") 15 | public class ShowTodoAction { 16 | private int id = 0; 17 | 18 | private Todo todo = new Todo(0, "in28Minutes", "Learn Spring MVC", 19 | new Date(), false); 20 | 21 | @Action(value = "show-todo", results = { @Result(name = "success", location = "todo.jsp") }) 22 | public String execute() { 23 | if (id > 0) { 24 | todo = new TodoService().retrieveTodo(id); 25 | } 26 | return "success"; 27 | } 28 | 29 | public Todo getTodo() { 30 | return todo; 31 | } 32 | 33 | public int getId() { 34 | return id; 35 | } 36 | 37 | public void setId(int id) { 38 | this.id = id; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/in28minutes/struts/WelcomeAction.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.struts; 2 | 3 | import org.apache.struts2.convention.annotation.Action; 4 | import org.apache.struts2.convention.annotation.Namespace; 5 | import org.apache.struts2.convention.annotation.Result; 6 | import org.apache.struts2.convention.annotation.ResultPath; 7 | 8 | @Namespace("/user") 9 | @ResultPath(value = "/WEB-INF/views/") 10 | public class WelcomeAction { 11 | @Action(value = "welcome", results = { @Result(name = "success", location = "welcome.jsp") }) 12 | public String execute() { 13 | return "success"; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/in28minutes/todo/service/TodoService.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.todo.service; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Date; 5 | import java.util.Iterator; 6 | import java.util.List; 7 | 8 | import com.in28minutes.model.Todo; 9 | 10 | public class TodoService { 11 | private static List todos = new ArrayList(); 12 | private static int todoCount = 3; 13 | 14 | static { 15 | todos.add(new Todo(1, "in28Minutes", "Learn Spring MVC", new Date(), 16 | false)); 17 | todos.add(new Todo(2, "in28Minutes", "Learn Struts", new Date(), false)); 18 | todos.add(new Todo(3, "in28Minutes", "Learn Hibernate", new Date(), 19 | false)); 20 | } 21 | 22 | public List retrieveTodos(String user) { 23 | List filteredTodos = new ArrayList(); 24 | for (Todo todo : todos) { 25 | if (todo.getUser().equals(user)) 26 | filteredTodos.add(todo); 27 | } 28 | return filteredTodos; 29 | } 30 | 31 | public Todo retrieveTodo(int id) { 32 | for (Todo todo : todos) { 33 | if (todo.getId() == id) 34 | return todo; 35 | } 36 | return null; 37 | } 38 | 39 | public void updateTodo(Todo todo) { 40 | todos.remove(todo); 41 | todos.add(todo); 42 | } 43 | 44 | public void addTodo(String name, String desc, Date targetDate, 45 | boolean isDone) { 46 | todos.add(new Todo(++todoCount, name, desc, targetDate, isDone)); 47 | } 48 | 49 | public void deleteTodo(int id) { 50 | Iterator iterator = todos.iterator(); 51 | while (iterator.hasNext()) { 52 | Todo todo = iterator.next(); 53 | if (todo.getId() == id) { 54 | iterator.remove(); 55 | } 56 | } 57 | } 58 | } -------------------------------------------------------------------------------- /src/main/resources/log4j.properties: -------------------------------------------------------------------------------- 1 | log4j.rootLogger=DEBUG, Appender1 2 | 3 | log4j.appender.Appender1=org.apache.log4j.ConsoleAppender 4 | log4j.appender.Appender1.layout=org.apache.log4j.PatternLayout 5 | log4j.appender.Appender1.layout.ConversionPattern=%-7p %d [%t] %c %x - %m%n 6 | -------------------------------------------------------------------------------- /src/main/resources/messages_en.properties: -------------------------------------------------------------------------------- 1 | welcome.message=Welcome in English 2 | todo.caption= Todo Caption in English -------------------------------------------------------------------------------- /src/main/resources/messages_fr.properties: -------------------------------------------------------------------------------- 1 | welcome.message=Welcome in French 2 | todo.caption= Todo Caption in French -------------------------------------------------------------------------------- /src/main/resources/struts.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 | /Error.jsp 10 | 11 | 12 | 13 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/views/common/footer.jspf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/views/common/header.jspf: -------------------------------------------------------------------------------- 1 | <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> 2 | <%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%> 3 | <%@ taglib prefix="s" uri="/struts-tags"%> 4 | 5 | 6 | Todos Application 7 | 9 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/views/common/navigation.jspf: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/views/error.jsp: -------------------------------------------------------------------------------- 1 | <%@ include file="common/header.jspf"%> 2 | <%@ include file="common/navigation.jspf"%> 3 |
4 | Application has encountered an error. Please contact support on ... 5 |
6 | 7 | <%@ include file="common/footer.jspf"%> 8 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/views/user/customized-error.jsp: -------------------------------------------------------------------------------- 1 | <%@ include file="../common/header.jspf"%> 2 | <%@ include file="../common/navigation.jspf"%> 3 |
Application has encountered an error.
4 |
Exception name: ${exception}
5 |
Exception stack trace: ${exceptionStack}
6 | 7 | <%@ include file="../common/footer.jspf"%> 8 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/views/user/list-todos.jsp: -------------------------------------------------------------------------------- 1 | <%@ include file="../common/header.jspf"%> 2 | <%@ include file="../common/navigation.jspf"%> 3 | 4 |
5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 21 | 22 | 26 | 27 | 28 | 29 |
TODO Caption
DescriptionDateCompleted
${todo.desc}${todo.done}Edit Delete 25 |
30 |
31 | Add 32 |
33 |
34 | <%@ include file="../common/footer.jspf"%> -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/views/user/todo.jsp: -------------------------------------------------------------------------------- 1 | <%@ include file="../common/header.jspf"%> 2 | <%@ include file="../common/navigation.jspf"%> 3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | <%@ include file="../common/footer.jspf"%> 19 | 20 | 25 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/views/user/welcome.jsp: -------------------------------------------------------------------------------- 1 | <%@ include file="../common/header.jspf"%> 2 | <%@ include file="../common/navigation.jspf"%> 3 |
4 | Welcome 5 |
6 | 7 | <%@ include file="../common/footer.jspf"%> 8 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | To do List 6 | 7 | 8 | struts2 9 | org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter 10 | 11 | 12 | 13 | struts2 14 | /* 15 | 16 | 17 | 18 | /WEB-INF/views/error.jsp 19 | 20 | -------------------------------------------------------------------------------- /workInProgress.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/in28minutes/Struts2StepByStep/ab8f6e72cad84c2bb6802b2873ea89222fce3206/workInProgress.zip --------------------------------------------------------------------------------