Auto-Generate a Secure Password in Java – Plain Java, Servlet, and Struts2
Generating a random password is a common requirement for user registration, password reset, and account creation flows. This tutorial shows three implementations: a plain Java utility class, a Java Servlet endpoint, and how to call it from a Struts2 action.
Approach: Build a Utility Class
The safest approach is to create a reusable PasswordGenerator utility that uses SecureRandom (cryptographically strong) instead of java.util.Random. A good password mixes uppercase letters, lowercase letters, digits, and special characters.
PasswordGenerator.java – Plain Java Utility
package com.java9r.util;
import java.security.SecureRandom;
public class PasswordGenerator {
private static final String UPPERCASE = "ABCDEFGHJKLMNPQRSTUVWXYZ";
private static final String LOWERCASE = "abcdefghjkmnpqrstuvwxyz";
private static final String DIGITS = "23456789";
private static final String SPECIALS = "@#$%!&*";
// Combined pool — note: ambiguous chars (0, O, l, 1, I) excluded
private static final String ALL_CHARS = UPPERCASE + LOWERCASE + DIGITS + SPECIALS;
private static final SecureRandom RANDOM = new SecureRandom();
/**
* Generate a password of the specified length.
* Guarantees at least one character from each category.
*/
public static String generate(int length) {
if (length < 8) throw new IllegalArgumentException("Minimum length is 8");
char[] password = new char[length];
// Ensure at least one from each category
password[0] = UPPERCASE.charAt(RANDOM.nextInt(UPPERCASE.length()));
password[1] = LOWERCASE.charAt(RANDOM.nextInt(LOWERCASE.length()));
password[2] = DIGITS.charAt(RANDOM.nextInt(DIGITS.length()));
password[3] = SPECIALS.charAt(RANDOM.nextInt(SPECIALS.length()));
// Fill the rest from the combined pool
for (int i = 4; i < length; i++) {
password[i] = ALL_CHARS.charAt(RANDOM.nextInt(ALL_CHARS.length()));
}
// Shuffle to avoid predictable positions
for (int i = length - 1; i > 0; i--) {
int j = RANDOM.nextInt(i + 1);
char tmp = password[i];
password[i] = password[j];
password[j] = tmp;
}
return new String(password);
}
public static void main(String[] args) {
System.out.println("Generated Passwords:");
for (int i = 1; i <= 5; i++) {
System.out.println(i + ": " + generate(12));
}
}
}
Output
Generated Passwords:
1: sK7@mRb!nY3D
2: G9!vTz#mCp5W
3: Lq&8Hn2$rXkM
4: Yw5@bN!tDm3Z
5: Px7#KvT&nR2s
Java Servlet – Generate Password via HTTP
package com.java9r.servlet;
import com.java9r.util.PasswordGenerator;
import javax.servlet.http.*;
import javax.servlet.*;
import java.io.IOException;
import java.io.PrintWriter;
public class PasswordServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String lengthParam = request.getParameter("length");
int length = 12; // default length
if (lengthParam != null) {
try {
length = Integer.parseInt(lengthParam);
} catch (NumberFormatException ignored) {}
}
String password = PasswordGenerator.generate(length);
response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");
PrintWriter out = response.getWriter();
out.print("{\"password\": \"" + password + "\", \"length\": " + length + "}");
out.flush();
}
}
web.xml (Servlet mapping)
<servlet>
<servlet-name>PasswordServlet</servlet-name>
<servlet-class>com.java9r.servlet.PasswordServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>PasswordServlet</servlet-name>
<url-pattern>/generatePassword</url-pattern>
</servlet-mapping>
Usage
GET /generatePassword → 12-character password
GET /generatePassword?length=16 → 16-character password
Struts2 Action – Generate Password
package com.java9r.action;
import com.java9r.util.PasswordGenerator;
import com.opensymphony.xwork2.ActionSupport;
public class PasswordAction extends ActionSupport {
private String generatedPassword;
private int length = 12;
public String execute() {
generatedPassword = PasswordGenerator.generate(length);
return SUCCESS;
}
public String getGeneratedPassword() { return generatedPassword; }
public int getLength() { return length; }
public void setLength(int length) { this.length = length; }
}
struts.xml
<action name="generatePassword"
class="com.java9r.action.PasswordAction">
<result name="success">/WEB-INF/jsp/password.jsp</result>
</action>
password.jsp
<%@ page contentType="text/html;charset=UTF-8" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head><title>Generated Password</title></head>
<body>
<h2>Generated Password</h2>
<p><strong><s:property value="generatedPassword"/></strong></p>
<form action="generatePassword" method="get">
Length: <input type="number" name="length" value="12" min="8" max="32">
<input type="submit" value="Generate New">
</form>
</body>
</html>
SecureRandom vs Random – Why It Matters
| Aspect | java.util.Random |
java.security.SecureRandom |
|---|---|---|
| Source of randomness | Pseudo-random (seed-based) | OS-level entropy (cryptographically strong) |
| Predictable? | Yes, if seed is known | No |
| Performance | Faster | Slightly slower (acceptable for passwords) |
| Use for passwords? | No — security risk | Yes — always use for security tokens |
Summary
The key to a good password generator is: use SecureRandom (not Random), exclude visually ambiguous characters (0, O, l, 1), guarantee at least one character from each required category (uppercase, lowercase, digit, special), and shuffle the result so the guaranteed characters are not always at fixed positions. Wrap this in a utility class so it can be called from plain Java, a Servlet, or a Struts2/Spring action without duplication.
Comments