I'm working on a simple Spring MVC web app that allows users to encrypt and decrypt messages with classical ciphers such as the shift or Caesar cipher. It also allows users to auto-decrypt a message using crypt-analysis and to press an example button that randomly pulls an example, for any given cipher, from a database. The 4 ciphers are Shift, Affine, Substitution, and Vigenere. Each cipher has plain text, cipher text, and a key(s). The key(s) can be integers or strings.

I have the following concerns about my app:

  1. My controller has 3 routes for each cipher. One is a GET for when the user navigates to the page. Another is POST with a direction for encrypting, decrypting, or auto-decrypting. The last is a GET for an example of a cipher. I've tried handling things in a better polymorphic way, but haven't had success, mostly due to the fact that ciphers can have one or multiple keys.
  2. My shift classes that contain the business logic are stateless and it seems unnecessary to create an object when all of the methods could just be static.
  3. Similar to #2, I've considered getting rid of the Value Objects and instead just have a POJO with the cipher business logic in it. However, my understanding is that a bean should not have business logic. Therefore, I separated the VO and the classes that contain the business logic for the ciphers.
  4. For the Shift and Affine Cipher, the keys (the shift amounts) have a specific boundary. The key for Shift has to be numbers 1-26 while Affine has to be a number relatively prime to 26. This is business logic and should not be defined in the view. Therefore, I made an array for the valid shift amounts that a user can enter. This array is a static final variable on my Domain Model. It is passed to the view and the view renders a drop down for each element in the array. In the case of an Affine Cipher, this would be the numbers relatively prime to 26. I'd appreciate insight on how I could handle this business logic.

I'll show relative code for a Shift Cipher.


public class ShiftVO {
    private String plainText, cipherText;
    private int shiftAmount;
    private int [] validShifts; //The possible shifts that a user can perform with a Shift Cipher (1-26)

    public String getPlainText() {
        return plainText;
    public void setPlainText(String plainText) {
        this.plainText = plainText;
    public String getCipherText() {
        return cipherText;
    public void setCipherText(String cipherText) {
        this.cipherText = cipherText;
    public int getShiftAmount() {
        return shiftAmount;
    public void setShiftAmount(int shiftAmount) {
        this.shiftAmount = shiftAmount;
    public int[] getValidShifts() {
        return validShifts;
    public void setValidShifts(int[] validShifts) {
        this.validShifts = validShifts;

ShiftCipher - Business logic for a shift cipher. As noted in #3 I'm considering getting rid of this class or make the methods static.

public class ShiftCipher {
    public final static int [] VALID_SHIFTS = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26};

    public String encrypt(String plainText, int shiftAmount) {
        //performs encryption
    public String decrypt(String cipherText, int shiftAmount) {
        //performs decryption

    public int autoDecrypt(String cipherText) {
        //performs auto decryption

CipherDAO - used to get a random cipher from the database as an example for the user

public class CipherDao {

    private SimpleJdbcCall procReadCipher;

    public void setDataSource(DataSource jdbc) {
        this.procReadCipher= new SimpleJdbcCall(jdbc);
    public ShiftVO getRandShift(){
        SqlParameterSource in = new MapSqlParameterSource();
        Map<String, Object> out = procReadCipher.execute(in);
        ShiftVO shiftVO = new ShiftVO();
        shiftVO.setCipherText((String) out.get("cipher_text"));
        shiftVO.setPlainText((String) out.get("plain_text"));
        shiftVO.setShiftAmount((Integer) out.get("shift_amount"));
        return shiftVO;

RandomCipherService - Service for communication to the DAO to retrieve random ciphers for examples

public class RandomCipherService {
    private CipherDao cipherDao;

    public void setOffersDao(CipherDao cipherDao) {
        this.cipherDao = cipherDao;

    public ShiftVO getRandomShift(){    
        return cipherDao.getRandShift();


public class CipherService {
    public enum CipherDirection {
    public void shift(ShiftVO shiftVO, CipherDirection cipherDirection){
        ShiftCipher shiftCipher = new ShiftCipher();
            if(cipherDirection == CipherDirection.ENCRYPT){
                String cipherText = shiftCipher.encrypt(shiftVO.getPlainText(), shiftVO.getShiftAmount());
            } else if(cipherDirection == CipherDirection.DECRYPT){
                String plainText = shiftCipher.decrypt(shiftVO.getCipherText(), shiftVO.getShiftAmount());
            } else if(cipherDirection == CipherDirection.AUTODECRYPT){
                int shiftAmount = shiftCipher.autoDecrypt(shiftVO.getCipherText());
                String plainText = shiftCipher.decrypt(shiftVO.getCipherText(), shiftAmount);
            } //Still need to add IllegalArgumentException
        } catch(Exception e){
            System.out.println("Error: " + e);



public class CipherController {

    private CipherService cipherService;
    private RandomCipherService randomCipherService;

    public void setCipherService(CipherService cipherService) {
        this.cipherService = cipherService;
    public void setRandomCipherService(RandomCipherService randomCipherService) {
        this.randomCipherService = randomCipherService;

    public String showShift(Model model){
            ShiftVO shiftVO = new ShiftVO();
            return "shift";

    @RequestMapping(value="/shift", method=RequestMethod.POST)
    public String shiftCipher(ShiftVO shiftVO
                        , @RequestParam("cipherDirection") String cipherDirection
                        , Model model) {
        cipherService.shift(shiftVO, CipherDirection.valueOf(cipherDirection));
        return "shift";

    public String randomShiftCipher(Model model){
        System.out.println("random shift");
        ShiftVO shiftVO = randomCipherService.getRandomShift();
        return "shift";


<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
<%@ taglib prefix="sf" uri="http://www.springframework.org/tags/form" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
    <title>Classical Cipher</title>
    <link href="${pageContext.request.contextPath}/assets/css/cipher.css" rel="stylesheet" type="text/css">

    <nav id = "navbar-ciphers">
      <ul class = "menu">
        <li><a href="${pageContext.request.contextPath}/shift">Shift</a></li>   
        <li><a href="${pageContext.request.contextPath}/affine">Affine</a></li>             
        <li><a href="${pageContext.request.contextPath}/substitution">Substitution</a></li>   
        <li><a href="${pageContext.request.contextPath}/vigenere">Vigenere</a></li>   
    <div id="main-content">
      <div id="cipher-input">
      <sf:form method="post" action="${pageContext.request.contextPath}/shift" commandName="shift">
        <div id ="shift-cipher-input" class="selected-cipher">
          <label> Shift Amount: </label>
          <select name="shiftAmount" id="shift-amount">
            <c:forEach var="validShift" items="${shift.validShifts}">
                <option value="${validShift}" ${validShift == shift.shiftAmount ? 'selected' : ''}>${validShift}</option>
        <label>Plain Text</label>
        <textarea name="plainText" id="plain-text" placeholder="Plain text"><c:out value="${shift.plainText}"></c:out></textarea>
        <label>Cipher Text</label>
        <textarea name="cipherText" id="cipher-text" placeholder="Cipher text"><c:out value="${shift.cipherText}"></c:out></textarea>
        <button type="submit" id="encrypt" name="cipherDirection" value="ENCRYPT">Encrypt</button>
        <button type="submit" id="decrypt" name="cipherDirection" value="DECRYPT">Decrypt</button>
        <button type="submit" id="auto-decrypt" name="cipherDirection" value="AUTODECRYPT">Auto Decrypt</button>
        <input type="button" id="clear-ciphers" value = "Clear">
     <input type="button"  onclick="${pageContext.request.contextPath}/randomshift" value="Randomshift">
    <form action="<c:url value="/randomshift" />" method="GET">
        <input type="submit" name="action" value="Random" />
    <script type="text/javascript" src="https://code.jquery.com/jquery-2.2.1.min.js"></script>
    <script type="text/javascript" src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>
    <script type="text/javascript" src="${pageContext.request.contextPath}/assets/js/cipher.js"></script>


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.