Matt RaibleMatt Raible is a writer with a passion for software. Connect with him on LinkedIn.

The Angular Mini-Book The Angular Mini-Book is a guide to getting started with Angular. You'll learn how to develop a bare-bones application, test it, and deploy it. Then you'll move on to adding Bootstrap, Angular Material, continuous integration, and authentication.

Spring Boot is a popular framework for building REST APIs. You'll learn how to integrate Angular with Spring Boot and use security best practices like HTTPS and a content security policy.

For book updates, follow @angular_book on Twitter.

The JHipster Mini-Book The JHipster Mini-Book is a guide to getting started with hip technologies today: Angular, Bootstrap, and Spring Boot. All of these frameworks are wrapped up in an easy-to-use project called JHipster.

This book shows you how to build an app with JHipster, and guides you through the plethora of tools, techniques and options you can use. Furthermore, it explains the UI and API building blocks so you understand the underpinnings of your great application.

For book updates, follow @jhipster-book on Twitter.

10+ YEARS


Over 10 years ago, I wrote my first blog post. Since then, I've authored books, had kids, traveled the world, found Trish and blogged about it all.
You searched this site for "struts". 749 entries found.

You can also try this same search on Google.

Remember Me Rocks!

I have to thank Erik for the idea of implementing "remember me" functionality. I just implemented it this morning on my current project, and it's already saving me time. I used to have to re-login each time after I re-deployed. No more, just refresh!! I love it - thanks Erik!

BTW, I ended up fixing the saving-bad-password problem by adding another cookie to the mix. This one is called authenticated and is set by my ActionFilter servlet, which filters my protected resources. Good stuff - I'll be adding it to struts-resume, and possibly Roller (is this a good feature to add?).

Posted in Java at Jan 14 2003, 09:37:29 AM MST 1 Comment

Simple Intentions turn into Remember Me Login

I woke up this morning, and had the simple intention of blogging about one of my favorite tools, The Color Schemer. If you're a wanna-be designer like me, it's awesome. It helps you match "like" colors and also allows you to select any color on your screen. It's one of my most invaluable web design tools. Putting a tip about this was my only hope at 4:30 when I sat down at this computer. Now it's 5:39.

Why am I still here? I got caught up in reading the Colorado Bloggers mailing list - which actually got some traffic yesterday. This is one of the first times I've received a message from the list. One of the members pointed me to a another Photo Album for the web. It's called Gallery and she has an example setup. Looks like it runs on PHP. Well that shouldn't have taken me an hour, right?

The activity that's filled my last hour has been wrestling with Erik Hatcher's request for "remember me" functionality in a J2EE app, using container-managed security. The good news is that I did get it working - here's how:

  1. First, I added a checkbox called "rememberMe" to my login.jsp. When the user clicks "submit", I do some JavaScript logic. This logic entails saving the username and password as cookies - but only if the rememberMe checkbox is checked. If rememberMe is checked, a cookie is set called "rememberMe" with a value of "true."
  2. Using Roller's BreadCrumbFiler (maps to /*), I added some logic to check for the existence of the "rememberMe" cookie, and if it exists, to route the user to "j_security_check?j_username="+usernameCookie+"&j_password="+passwordCookie.

This all worked fine and dandy right off the bat - took me about 10 minutes to implement. The problem was that a user couldn't "logout." So I've spent the last hour (now it's been an hour and 1/2) with my own ignorance trying to delete cookies (and doing null checks and such) so users could logout. And I just got it working - fricken sweet! What a way to start the day! The only problem I could see now is if a user tries a username/password and selects "remember me", but then closes their browser. The BreadCrumbFilter will keep trying to authenticate them - yep, I just verified that that's a problem. It's also a problem when they enter an invalid password and select rememberMe.

One way to solve this is to not set the "rememberMe" and "password" cookies until someone has successfully authenticated. Maybe I could use the breadcrumbs in the BreadCrumbFilter to check the last URL accessed, and if it's already j_security_check, don't do the routing. Anyway, here's the code that does the heavy lifting in BreadCrumbFilter:

Cookie rememberMe = RequestUtil.getCookie(request, "rememberMe");
// check to see if the user is logging out, if so, remove the
// rememberMe cookie and password Cookie
if (request.getRequestURL().indexOf("logout") != -1 && 
	(rememberMe != null)) {
    if (log.isDebugEnabled()) {
        log.debug("deleting rememberMe-related cookies");
    }

    response =
        RequestUtil.deleteCookie(response,
                                 RequestUtil.getCookie(request,
                                                       "rememberMe"));
    response =
        RequestUtil.deleteCookie(response,
                                 RequestUtil.getCookie(request,
                                                       "password"));
}

if (request.getRequestURL().indexOf("login") != -1) {
    // container is routing user to login page, check for remember me cookie
    Cookie username = RequestUtil.getCookie(request, "username");
    Cookie password = RequestUtil.getCookie(request, "password");

    if ((rememberMe != null) && (password != null)) {
        // authenticate user without displaying login page
        String route =
            "j_security_check?j_username=" +
            RequestUtils.encodeURL(username.getValue()) +
            "&j_password=" +
            RequestUtils.encodeURL(password.getValue());

        if (log.isDebugEnabled()) {
            log.debug("I remember you '" + username.getValue() +
                      "', authenticating...");
        }

        response.sendRedirect(response.encodeRedirectURL(route));

        return;
    }
}

I can post the code for RequestUtil if you need it. The class RequestUtils (for encoding URLs) is a Struts class.

Posted in Java at Jan 14 2003, 06:07:21 AM MST 4 Comments

My First Attempt at ConvertUtils

My first attempt at using ConvertUtils is turning out to be a painful one - most likely due to my own ignorance. Let's see if you can help me out. I have a Hibernate Bag, which is really a java.util.List on my User object. When I run the User object through XDoclet, I create a UserForm (extends ValidatorForm). The form has an ArrayList on for any instances of List or Set on the object (set through a custom struts_form.xdt template). So I created a ListConverter to convert a List object to an ArrayList. Sounds pretty simple right?! Here's my ListConverter.java:

public class ListConverter implements Converter {
    //~ Instance fields ========================================================

    protected Log log = LogFactory.getLog(ListConverter.class);

    //~ Methods ================================================================

    /**
     * Convert a List to an ArrayList
     *
     * @param type the class type to output
     * @param value the object to convert
     */
    public Object convert(Class type, Object value) {
        if (log.isDebugEnabled()) {
            log.debug("entering 'convert' method");
        }

        // for a null value, return null
        if (value == null) {
            return null;
        } else if (value instanceof Set && (type == Set.class)) {
            return new ArrayList((Set) value);
        } else if (value instanceof List && (type == List.class)) {
            return new ArrayList((List) value);
        } else {
            throw new ConversionException("Could not convert " + value
                                          + " to ArrayList!");
        }
    }
}

When I run BeanUtils.copyProperties(userForm, user), I get:

Could not convert cirrus.hibernate.collections.Bag@e2892b to ArrayList!

On another class, where I am trying to convert a List of Longs, I get:

Could not convert [-1, 1, 30129] to ArrayList!

I'm registering my custom converter in a static block of my BaseManager class. My *Manager classes do all the conversions, so this seems logical:

static {
    ConvertUtils.register(new StringConverter(), String.class);
    ConvertUtils.register(new LongConverter(), Long.class);
    ConvertUtils.register(new ListConverter(), ArrayList.class);
	
    if (log.isDebugEnabled()) {
        log.debug("Converters registered...");
    }
}

Since I'm in a major time crunch, I'll try simply making my getter/setters on my UserForm to be List. I'd like to use ConvertUtils though, so hopefully someone has a solution.

This brings me to a RANT and I think it's my first official one. My last three projects have always started small, and the goal has always been a prototype of functionality. A prototype that turns into a production system. All fricken three of them. All were supposed to take about 3 months to develop initially. The last two projects took at least 6 months. This one has a one month deadline, but the scope is a lot smaller than the previous two. But still, it's always the same scenario - the clients want a prototype, but turn it into a production system. Since it's a prototype, I tend to write "workarounds" for design patterns (see above) that I can't figure out. Is this good? It probably doesn't hurt since no one will ever look at my code - right?! When's the last time you looked at a co-workers code? (The more == the better). And the truth is, as long as it works - it's probably good enough. However, I as a developer, get heartburn when I think about maintaining the system that I created under the impression that it was a prototype. Maybe one of these days I'll figure out all the best practices to creating a robust web application, and then I'll know everything - so I won't have to write workarounds for my lack of knowledge. If you see some pigs flying, you can think to yourself - "Wow, Raible must've figured it all out" ;-)

Posted in Java at Jan 11 2003, 04:04:43 PM MST 1 Comment

The Road to Happiness

As you may have noticed, I didn't write anything on this site yesterday. Believe me, I wanted to, especially after reading this call to arms for Struts Developers. But instead, I did some work on my New Years resolution. First I went to the gym and played basketball (yeah, you really wanted to hear about that ;-) with one of greatest friends, Shane Murphy. Then I came home and relaxed a bit. As I was getting ready to jump on the ol' computer and blog about how much I loved Hibernate and such, Julie asked me if I'd change Abbie. I said "Sure!" As I was changing her, she smiled at me and giggled. If you have children - you know how cool this is - especially when it's one of the first times. She started smiling a couple of weeks ago - but now you can tell she really means it. So I said, "happiness it is," and I read her a story (Father's Flying Flapjacks) and played with her for a good hour. We were sticking our tongues out at each other and had an awesome time. She is the coolest kid in the world! What an sweet way to end the day. I'm happy to say that I ended up falling asleep (with Abbie on my arm) without getting on the computer.

Posted in General at Jan 10 2003, 09:44:29 PM MST 2 Comments

Lovin' Hibernate

I'm loving Hibernate after using it for a few weeks. I'm sure I'd like it a lot more if I'd break down and read the documenation. But nope, I'm still only reading it on a JIT basis. I feel about Hibernate like I first felt about Struts. It's fun and easy to work with and makes my persistent-life soooo much easier. Now if I could only break down and learn something about ConvertUtils.

Posted in Java at Jan 10 2003, 09:29:37 PM MST Add a Comment

My Favorite Restaurant: Chipotle

Chipotle Mexican Grill I was watching The Osbournes this evening and found it hilarious that Ozzy is addicted to Chipotle Burritos. He's eating 2-3 per day! I can understand his addiction, as this by far my favorite meal. The first Chipotle was actually started right by DU, and my senior year I lived on the same block as it. It was awesome to have it on the way home from class. They've come a long way since then, and now Chipotle restaurants can be found all over the US.

I hope there's one in Florida by the time we move there this summer. Those are the two things I'll miss the most - Chipotle and good Microbrews. Of course I'll miss all the awesome mountain biking and skiing - but we'll be back here someday, and I'm sure I can enjoy the beach for awhile. The last couple of days here in Denver have been awesome - 70 yesterday and 75 today!! How fricken sweet is that - global warming is working!

Posted in General at Jan 08 2003, 08:50:08 PM MST 2 Comments

Struts Resume @ Sourceforge.net

I'm in the midst of checking in my struts-resume app to the struts-apps project at sourceforge.net. I hate to admit it, but I'm doing it the ugly way. I have a ~12MB lib directory that contains all the 3rd party jars used in this application. Ugh, I wish I was using Maven now. I figure you gotta start somewhere though - so I might as well get it all in there and clean it all up later.

Posted in Java at Jan 07 2003, 10:46:01 PM MST Add a Comment

Upgrading to Struts 1.1b3 - Tips

I upgraded one of my client's applications from Struts 1.1b2 to Struts 1.1b3 tonight. It was a small headache, but not too bad. As far as the differences b/w 1.1b2 and 1.1b3 - they're pretty significant. Some classes/methods are downright gone - not just deprecated, but gone. Oh well, that's why it's a beta - and it's free, so who's complaining? I'll try to remember a few issues I found. The first is how to create a DynaActionForm. The code below worked with 1.1b2:

DynaActionForm messageForm = 
    (DynaActionForm) DynaActionFormClass.getDynaActionFormClass(
                     Constants.MESSAGE_KEY).newInstance();

But the getDynaActionFormClass method is now gone, so you have to use this:

FormBeanConfig cfg =
    mapping.getModuleConfig()
           .findFormBeanConfig(Constants.MESSAGE_KEY);

DynaActionForm messageForm =
    (DynaActionForm) DynaActionFormClass.createDynaActionFormClass(cfg)
                                        .newInstance();

A few deprecation errors cropped up as well.

  • Action.MESSAGE_KEY -> Globals.MESSAGE_KEY
  • Action.ERROR_KEY -> Globals.ERROR_KEY
  • org.apache.struts.validator.StrutsValidatorUtil -> org.apache.struts.validator.Resources

Finally, I found an issue with using BeanUtils.populate(dest, orig). It worked fine with 1.1b2, but throws a NPE with 1.1b3. I replaced this with BeanUtils.copyProperties(dest, orig) and everything works as it should. My guess (from doing a toString() on the orig) is that "multipartRequestHandler=null" was messing things up.

It's interesting doing maintenance/enhancements on code that I wrote a year ago. I've learned sooooo much since then. I wish I could go back and re-factor a bunch, but my client would never go for it - it works right?! Maybe I'll refactor some for kicks - just to see if it's possible. I'd love to replace a few DAOMySQL's with DAOHibernate's ;-)

Posted in Java at Jan 06 2003, 11:16:48 PM MST 6 Comments

I'm lovin' Eclipse and its plugins (CVS, Hibernate)

After working with Eclipse pretty heavily for the last week - I am beginning to become one of those guys that cannot live without an IDE. It's unfortunate in one sense, but it's great because it sure is saving me a lot of time. I love the "Organize Imports" feature, especially on the package level. Use it with caution if you've got generated classes - or add the generated classes to your classpath. I also really like the Jalopy Beautifier. I'm sure IDEA has these features too - if it doesn't, it should! Another cool plugin I found last week was one from the Eclipse team to hide CVS directories.

This morning, I found that the Hibernate team has released a new plugin for Eclipse - the Hibernator.

*** Hibernator - Hibernate plugin for Eclipse ***

Provides an Eclipse view to create and edit Hibernate mapping files (.hbm.xml).

Note this plugin will only work with Eclipse 2 (WSAD 5) and above

* Installation

- Unzip hibernator-0.9.zip into <eclipse-install>/plugins - Restart Eclipse

* Using the plugin

Go to menu Window->Show View->Other and select Hibernator

Open up some Java source and the plugin will either display the mapping file <class-name>.hbm.xml or a generated version

To save the contents of the mapping file right click in the window and select "Save"

Report any bugs / Submit patches to - http://sourceforge.net/projects/hibernator.

I doubt I'll use this as I'm using XDoclet to generate my Hibernate mapping files from POJOs. However, the CodeGenerator for Hibernate is being re-vamped to allow for generation of .java files from an .hbm.xml file. Now if I could hook this into generation of Struts' ValidatorForms, I might actually use it.

Posted in Java at Jan 06 2003, 07:50:12 AM MST Add a Comment

Struts Resume 0.5 Released!

I was up until 7:00 a.m. this morning finishing the struts-resume example application for my Struts chapter. I finally did it - I'm done. At least for now. I'd love to set a demo up on this server, but it requires a MySQL database, and I don't want to pay Keith the $20 to setup another database instance for me. I know, I know - Why don't I use HSQL? Because I just finished the damn application, and I need to convince myself to not touch it for at least a few days, or I'll never get anything else done (like cleaning my desk and hitting the gym).

Short-term (next 2-3 week) goals for this project are:

  • Abstract the good stuff out of struts-resume for AppFuse. They're really the same thing right now, and I'll need to trim it down a bit so there's only CRUD on a user or something like that.
  • Get it into the Struts Project's CVS at SourceForge.net. Ted Husted made me a committer, now I just have to do it. I'd rather check in appfuse than struts-resume, so the previous step is a must.
  • Change Struts to use path-mapping (/do/*) rather than extension-mapping (*.do). The tricky part is making this work with modules.
  • Code cleanup and Javadocs. Use checkstyle to make everything peachy-keen.

I don't believe it's important to fully flush out the features in the application at this point - that might overwhelm users in the end - maybe in a couple months I'll get around to doing that. You can bet I'll get super motivated right around the time I'm looking for a new gig! I'm expecting this in June, so might be awhile.

Posted in Java at Jan 05 2003, 01:05:05 PM MST Add a Comment