rr_lesson_1.war Introduction
The first three lessons are for true beginners to Struts. Each lesson introduces some new concepts and each successive lesson required you to have mastered the content of the previous lesson. These first lessons are meant to be very basic to help the beginner get a handle on the Struts concepts without getting side-tracked. If you have previous experience coding Struts applications, you probably will want to jump to some of the more intermediate level lessons.
Concepts introduced in Lesson 1:
Requirements
This application requires an application server that implements the Servlet 2.4 and JavaServer Pages 2.0 specifications. The examples should all work on Tomcat 5.x (Discussed in next section). Please do not e-mail about getting your application to run on a server other than Tomcat. The source code (and an Ant build file) is provided for all the lessons so you should be able to build a war from the source and run it on you application server of choice.
Setting up your environment
You'll need to have an application server installed on your local machine. The war included with this demo will run on Tomcat 5.0 and should run on Tomcat 5.5 as well. I'm not going to cover installing Tomcat, but it's really simple. On Windows, I suggest you just get the zip file rather than exe. Simply unzip tomcat into your C: drive and then you can stop start it by running the startup.bat and shutdown.bat files in the bin directory. (You can use the exe but I'd opt to not run Tomcat as a Service when you see that as a selection choice.)
If you have Tomcat installed, typically you'll want to build your application outside of the webapps directory in mabye a local projects directory. You would then probably using something like Ant to create a war file that moves it to the tomcat webapps directory, or you might simply configure Tomcat to point to your local application (in Tomcat 5.0 you can do this from the server.xml). However, to simplfy our proces here, I'm going to have you build the application directly in the webapps folder of Tomcat. When you are done compiling your code you can then just start tomcat and you should be all set. Obviously, if you are familiar with developing web applications, feel free to do things the more correct way. Also if you plan to use the build script in the source code, you'll definitely want to build this application outside of the Tomcat webapps directory since the build file assumes this and will deploy a war to your Tomcat webapps dir.
The basic directory structure should look like this:
Next you'll need to put some jars in your WEB-INF/lib directory. The following jars are needed:
The latest commons jar files commons-beanutils, commons-digester, commons-logging can be found here http://jakarta.apache.org/commons/, but it's esaier to just download the latest Struts Action Framwork http://struts.apache.org/acquiring.html and just use the commons jars that are in the example apps provided with Struts. Obviously you should get the latest struts jar from there as well. JSTL jars (standard, jstl) http://cvs.apache.org/builds/jakarta-taglibs/nightly/ Employee
Create Employee.java in src/net/reumann directory.
Our simple application is going to mimick inserting an Employee, which in real life would typically be an insert to a database. Since we are dealing with an employee that we want to insert, we need a way to store information about this Employee that we could hand off to a business object (the model layer of MVC). Our model layer will be responsible for doing the actual insert. The above Employee bean is the class that will hold this Employee information. Since this POJO (plain old java object) will transfer stored information from one part of our application to another it is often called a Data Transfer Object (DTO) or Value Object.
EmployeeService
Create EmployeeService.java in src/net/reumann directory.
A Service class isn't absolutely essential to your application, but I find it a good practice to use some kind of intermediate class between the Struts Action class (which you'll soon see) and your backend persistence layer - which is usually some kind of Data Access Object (DAO). Your service class is where you would do business logic operations before handing your valueObject/DTO off to the persistence layer. (In a real life application you should probably also create an interface for your Service class implementations. I skipped that to keep this lesson as short as possible.)
We don't do anything in our service class here except return the Employee object we are given.
EmployeeForm (Struts ActionForm)
Create EmployeeForm.java in src/net/reumann directory.
We already created an Employee object to hold the employee information that will get passed to our EmployeeService class. That Employee object was a true POJO that contained the correct data types of our Employee. For example, there was an "Integer" age in our Employee object. Web forms, however, will only submit data as Strings in the Request since that's just the limitation of HTTP. Struts uses an ActionForm object to capture what the user submits on a JSP form (You'll see this more clearly when we discuss the struts-config and the employeeForm.jsp). You want to use String properties for the properties in your ActionForms since Struts will actually use this ActionForm to help repopulate your JSP page with the values the user inputted if validation fails. If you were to use properties other than Strings in your ActionForm, you will not get those values preserved for you when validation fails. (Form validation is covered in the next lesson).
web.xml
Create web.xml and place in the WEB-INF directory.
The first thing to notice is the servlet mapping for our action. The url-pattern is *.do. This means all of our urls that end in .do are going to be handled by the org.apache.struts.action.ActionServlet. In short, this ActionServlet is going to figure out which of our Action classes to call based on the mapping it finds in the struts-config.xml file (discussed in next section). You do not have to make your mapping *.do, but often by convention *.do is used.
The MessageResources declaration is a file that will be used to display text in our JSPs. (It is also used to provide the correct message for generating messages or errors when using ActionMessages, but that is not covered in this lesson). You'll see in the next section that this resource file is also declared in our struts-config file. The reason it is in both places is that in order for us to use the JSTL format tag, instead of using the Struts bean:write tag, this file needs to be defined in our web.xml as well as our struts-config.xml.
struts-config.xml
Create struts-config.xml and place in the WEB-INF directory.
The struts-config file is where you define the flow of your application - what ActionForms to associate with different Action classes that you'll go to and what the posssible outcomes are in regard to where you forward to when you leave an Action. I know I have not covered the "Action" class yet, but for now just think of it as Servlet that is going to handle our Request from either a form submission or clicking on a URL. The action paths that you see above can be called from form submits or URLs.
Disecting the /insertEmployee mapping, you'll first notice "type." The type declaration defines what Action class we are going to forward to when the /insertEmployee pattern is found. If a URL is defined with insertEmployee.do or we are defining a struts form to submit to insertEmployee, this mapping will be looked up by the Struts ActionServlet and we will forward or submit to InsertEmployeeAction. This will become more clear shortly. The "name" attribute tells us which form-bean to use to capture Request paramaters. "scope" tells us whether or not to store the ActionForm in reuqest or session scope (always start out using request scope and only later if requirements dictate, should you change to session scope.) "validate" determines whether or not we want to use the validation framework to automatically validate our form (another lesson covers this). Finally, we can define serveral "forwards." When we leave our InsertEmployeeAction we can look up "success" and we will thus be forwarded to confirmation.jsp. If we wanted, we could add other forwards here as well. Maybe if things went wrong in our InserEmployeeAction we might want to return an "error" forward, which if we defined one in our mapping, could forward us to "error.jsp." Using these forwards allows for nice, flexible, and easy to maintain code. If later on you decide you wanted to go somewhere else after a "success," you simply change the path in the forward section and you are done. No need to mess with any Java files.
You always want to go through an Action during the flow of your web application. That means you should not be linking directly to .jsp files, but instead your link should map to an Action in the struts-config. So for example, the URL "/rr_lesson_1/setupEmployeeForm.do" is going to end up fowarding to /employeeForm.jsp. It might be confusing that the action-mapping declaration for /setupEmployeeForm is so short and the other is much longer. That is because Struts provides a short-cut when all we want to do is use an Action to 'get to another page.' When /setupEmployeeForm is called, behind the scenes Struts is using an ActionForward class to get our forward definition (/emploeeForm.jsp) picked up.
In this first lesson, we really aren't doing any "set up" of our EmployeeForm, but in a later lesson we will so I kept this mapping with the same 'setupEmployeeForm'. However, this also illustrates a good point of why you should ALWAYS go through an Action (defined in your struts-config file). What if later on we decided "You know what, instead of going right to the 'employee.jsp' file when /setupEmployeeForm.do is called, I really want to go an Action class and do some 'stuff.'" Well, in our case it's super easy, we just add more info like you see in the /insertEmployee section. However, if instead we did not have the <action path="/setupEmployeeForm" forward="/employeeForm.jsp"/> section, and instead we maybe had a bunch of links in our JSPs that went directly to employeeForm.jsp, we would have to find ALL of those links and change them to reflect the mapping that we end up putting in the struts-config. Bottom line: always go through an Action, do not link to pages directly.
InsertEmployeeAction
Create InsertEmployeeAction.
The main classes used in the Struts framework are those of org.apache.struts.action.Action. The Action classes are the true concrete bridges bewteen the client's request and calls to other business logic (DAOs, Service classes, etc). You'll see in future lessons that there are different types of Action classes (such as the DispatchAction) but for this basic lesson we are going to use the standard Action class that will handle one particular type of business operation the client wants to perform (in this case, the insert of an Employee).
Remember back to our action mapping in the struts-config file:
The path attribute will correspond to the "action" we will define in our JSP form for our form to submit to. When the form is submitted our request will make it to InsertEmployeeAction. When it exits the InsertEmployeeAction it will forward to confirmation.jsp by looking up the foward name "success."
The Action class has one method for us to worry about "execute(..)." When we submit our JSP page, the behind the scenes Struts stuff (ActionServlet and RequestProcessor) will find this Action class that we associated with the /insertEmployee action in the struts-config.xml file and the execute method will be called. Since the /insertEmployee action mapping defined EmployeeForm to be associated with this Action, the InsertEmployeeAction will have this form bean of type ActionForm, so we first cast this into type EmployeeForm in our execute method. Now we want to get the information in our EmployeeForm into our Employee object so we can pass that off to our back-end layer (our Service class. The "M" Model in MVC). We created an instance of Employee and then, like magic, we can use BeanUtils (from the Jakarta commons package) to transfer the data from EmployeeForm into the Employee object with one easy line: BeanUtils.copyProperties( employee, employeeForm ). This is a HUGE time saver, for if you were not going to use BeanUtils (or PropertyUtils) then you would normally build a helper class to do all the 'get and set' stuff and all the data type conversions (a real pain, especially for large beans). (Side Note: There are some issues with BeanUtils that I'm not happy about when doing conversions, mainly in regard to how it handles wrapper types (Integer,Double,etc) and not keeping them as null when they need to be).
After copyProperties(), the now populated Employee obect is passed off to the service object and the insert would be done. (We'll learn more in a later lesson about dealing with Exceptions that your model/business objects may throw). After the insert is done the Employee is put into Request scope so we could use the employee information for display purposes on the resulting confirmation.jsp.
The last thing to notice is that we need to return an ActionForward object which will tell our behind -the-scenes controller where we should forward to when the execute method is completed. In this case I want to forward to whatever I defined as "success" in my struts-config mapping for this action. Calling mapping.findFoward("success") will return an ActionForward object based on looking up the foward pararmeter in our mapping that matches "success" (in this case /confirmation.jsp). (Note: Rather than hard-code the word "success" here you should create a Constants class/interface that has these commonly used String variables).
MessageResources
Create MessageResources_en.properties in /src directory.
In our web.xml we declared:
and in struts-config.xml:
This tells our application that we are using a resources properties file that will be located in our WEB-INF/classes directory. (Remember to also make sure this file is in your src directory and make sure that your IDE or build script copies it over to classes when you do a build.) This file is used to hold display labels for our JSPs. It allows us to not have to hard code titles, error messages, button names, etc. If you notice the actual name of the file we are using is MessageResources,b>_en>.properties but we only declared the name "MessageResources" in our web.xml and struts-config file. This is because we can provide different Messages files based on diferent locales ( _fr, _de, etc.)
rr.css
Create rr.css in rr_lesson_1 directory.
index.jsp
Create index.jsp in rr_lesson_1 directory.
The first page the user comes to is our index page. All it does is provide a link for them to click on to add an employee. Up top we define the JSTL and struts tags that we are going to use. We use the c:url tag to help create our link to our style sheet. The url tag is nice since it figures out our app context name for us so we don't have to hardcode it. If we now decide we want to change the name of our application, we don't have to mess with changing the name in our links.
Notice I'm using the JSTL fmt tag for displaying the message from our MessageResources file. We could have used the Struts bean:write tag, but I like to stick to using JSTL wherever possible.
Finally, our link to setupEmployeeForm.do is defined using the c:url tag so that we generate the full context name (rr_lesson_1) automagically. Rememeber since there is a *.do extension that url will be looked up in the struts-config and if you remember it will bring us to the employeeForm.jsp
employeeForm.jsp
Create employeeForm.jsp in rr_lesson_1 directory.
Notice we need to use the Struts html:form tag when working with a Struts form. Our form tag will associate our AcionForm to this form based on our action mapping in our struts-config file that matches our form action (in this case "insertEmployee".) (You don't need to provide the .do suffix in the form action definition, that's only for URLs).
Our html:text form elements are used with the propety attribute which will get any values that are set in our EmployeeActionForm. (**The property name has to match the same property name in the ActionForm.**) In this case since the user hasn't entered anything our fields will be blank, but you'll see in future examples how this won't always be the case, such as when you go to an "edit" page.
confirmation.jsp
Create confirmation.jsp in rr_lesson_1 directory.
Our confirmation page simply displays the data contained in our Employee value object that we put in Request scope after doing the insert in our InsertAction class. Note the use of the JSTL c:out tag to display the bean properties of our Employee object. Remember the Employee bean was set into the Request in the Action with the name "employee." We thus need to use that name when accessing the properties of the bean ( ie. employee.name ).
|