返回文章列表文章索引阅读全文
STARBLOG / 阅读手记
Java

My First Experience Using the Struts2 Framework for Web Development in 2020

SliiyStruts2 aka sb-struts2, because struts is really too hard to use (maybe it was great many years ago, but looking at it now, other frameworks have completely crushed it) Preface I never thought I'd still have to deal with this struts framework. From the very beginning of learning web I strongly resisted this kind of ancient, user-hostile framework, but to help my girlfriend with a school assignment I still had to get into it. However, the business code that only took half an hour to write took me half a day of debugging to successfully run, because I wasn't familiar with this framework and Java's whole ecosystem...

曦远 (DealiAxy)约 33 分钟
目录9 个章节

SliiyStruts2

aka sb-struts2, because struts is really too hard to use (maybe it was great many years ago, but looking at it now, other frameworks have completely crushed it)

Preface

I never thought I'd still have to deal with this struts framework. From the very beginning of learning web I strongly resisted this kind of ancient, user-hostile framework, but to help my girlfriend with a school assignment I still had to get into it. However, the business code that only took half an hour to write took me half a day of debugging to successfully run, because I wasn't familiar with this framework and Java's whole ecosystem...... (so exhausting)

Getting Started

First use IDEA to create a struts2 project, but then came the pitfall: the project created by IDEA is missing a package. Please download it yourself from the Maven repository. Specifically, this package is missing

javassist-3.26.0-GA.jar

Then you can start writing code......

References for learning the Struts2 framework:

This article is well written and very detailed, and it even has examples. Follow along and you can implement a simple struts framework yourself......

Configuration

First write a simplest IndexAction, mainly for initializing the database. The code is as follows:

package cn.deali.action;

import cn.deali.utils.Database;
import com.opensymphony.xwork2.ActionSupport;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class IndexAction extends ActionSupport {
    private final static Logger logger = LoggerFactory.getLogger(IndexAction.class);

    @Override
    public String execute() throws Exception {
        System.out.println("Index Action");
        logger.info("Index Action");

        // 初始化数据库
        if (Database.init()) {
            Database.eraseData = false;
            return SUCCESS;
        } else
            return ERROR;
    }
}

After writing the Action you still need a matching jsp page. This is called the MVC design pattern, frontend-backend separation (fake)......

<%--
  Created by IntelliJ IDEA.
  User: DealiAxy
  Date: 2019/11/17
  Time: 10:23
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>用户管理系统</title>
</head>
<body>
<h1>用户管理系统</h1>

<a href="Login.action">登录</a>
<a href="SignIn.action">注册</a>
<a href="User.action">修改密码</a>

</body>
</html>

I didn't include the other code due to length. There's a GitHub address at the end of this article; you can refer to it if needed

Then you can configure struts2, like this......

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE struts PUBLIC
        "-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
        "http://struts.apache.org/dtds/struts-2.5.dtd">

<struts>
    <package name="cn.deali.action" namespace="/" extends="struts-default">
        <default-action-ref name="Index"/>
        <action name="Index" class="cn.deali.action.IndexAction" method="execute">
            <result name="success">main.jsp</result>
            <result name="error">error.jsp</result>
        </action>
    </package>
</struts>

The <default-action-ref name="Index"/> is something I learned later, the default action. At first I thought it was like other frameworks, just define a "/" route and that would be it, but I ended up shooting myself in the foot and spent half a day debugging without it working.

References:

Logging

At first I used log4j, felt a bit frustrating, then I remembered I'd used slf4j before. Although they're not the same concept, slf4j+slf4j-simple is really easy to use and convenient (ps: if you need better performance you can use logback, hhh). log4j configuration is really troublesome, and embedding it into the tomcat server—anyway this is just a homework assignment, no need to make it too complicated.

And slf4j's output templates are also very convenient, at least you don't have to concatenate strings like with log4j.

References for logging:

I'll also put up my own Log4J configuration here, even though I didn't end up using it.

# 配置根Logger:设定日志记录的最低级别,
log4j.rootLogger=DEBUG, stdout, logfile,ERROR
log4j.category.org.springframework=ERROR
log4j.category.org.apache=INFO
log4j.logger.org.hibernate=ERROR
# 输出到控制台
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
# 指定日志信息的最低输出级别,默认为DEBUG
log4j.appender.stdout.Threshold=ERROR
# 表示所有消息都会被立即输出,设为false则不输出,默认值是true
log4j.appender.stdout.ImmediateFlush=true
# 可以灵活自定义布局模式
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
# 默认值是System.out。
log4j.appender.stdout.Target=System.out
# 设定以怎样的格式显示消息
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n

Database

The database is once again the familiar favorite SQLite. I use this every time anyway, hhh......

For using SQLite in Java, you can refer to:

Here's my SQLiteHelper utility class code:

package cn.deali.utils.sqlite;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

/**
 * sqlite帮助类,直接创建该类示例,并调用相应的接口即可对sqlite数据库进行操作
 * <p>
 * 本类基于 sqlite jdbc v56
 *
 * @author haoqipeng
 */
public class SQLiteHelper {
    private final static Logger logger = LoggerFactory.getLogger(SQLiteHelper.class);

    private Connection connection;
    private Statement statement;
    private ResultSet resultSet;
    private String dbFilePath;

    /**
     * 构造函数
     *
     * @param dbFilePath sqlite db 文件路径
     * @throws ClassNotFoundException
     * @throws SQLException
     */
    public SQLiteHelper(String dbFilePath) throws ClassNotFoundException, SQLException {
        this.dbFilePath = dbFilePath;
        connection = getConnection(dbFilePath);
    }

    /**
     * 获取数据库连接
     *
     * @param dbFilePath db文件路径
     * @return 数据库连接
     * @throws ClassNotFoundException
     * @throws SQLException
     */
    public Connection getConnection(String dbFilePath) throws ClassNotFoundException, SQLException {
        Connection conn = null;
        Class.forName("org.sqlite.JDBC");
        conn = DriverManager.getConnection("jdbc:sqlite:" + dbFilePath);
        return conn;
    }

    /**
     * 执行sql查询
     *
     * @param sql sql select 语句
     * @param rse 结果集处理类对象
     * @return 查询结果
     * @throws SQLException
     * @throws ClassNotFoundException
     */
    public <T> T executeQuery(String sql, ResultSetExtractor<T> rse) throws SQLException, ClassNotFoundException {
        try {
            resultSet = getStatement().executeQuery(sql);
            T rs = rse.extractData(resultSet);
            return rs;
        } finally {
            destroyed();
        }
    }

    /**
     * 执行select查询,返回结果列表
     *
     * @param sql sql select 语句
     * @param rm  结果集的行数据处理类对象
     * @return
     * @throws SQLException
     * @throws ClassNotFoundException
     */
    public <T> List<T> executeQuery(String sql, RowMapper<T> rm) throws SQLException, ClassNotFoundException {
        List<T> rsList = new ArrayList<T>();
        try {
            resultSet = getStatement().executeQuery(sql);
            while (resultSet.next()) {
                rsList.add(rm.mapRow(resultSet, resultSet.getRow()));
            }
        } finally {
            destroyed();
        }
        return rsList;
    }

    /**
     * 执行数据库更新sql语句
     *
     * @param sql
     * @return 更新行数
     * @throws SQLException
     * @throws ClassNotFoundException
     */
    public int executeUpdate(String sql) throws SQLException, ClassNotFoundException {
        try {
            int c = getStatement().executeUpdate(sql);
            return c;
        } finally {
            destroyed();
        }

    }

    /**
     * 执行多个sql更新语句
     *
     * @param sqls
     * @throws SQLException
     * @throws ClassNotFoundException
     */
    public void executeUpdate(String... sqls) throws SQLException, ClassNotFoundException {
        try {
            for (String sql : sqls) {
                getStatement().executeUpdate(sql);
            }
        } finally {
            destroyed();
        }
    }

    /**
     * 执行数据库更新 sql List
     *
     * @param sqls sql列表
     * @throws SQLException
     * @throws ClassNotFoundException
     */
    public void executeUpdate(List<String> sqls) throws SQLException, ClassNotFoundException {
        try {
            for (String sql : sqls) {
                getStatement().executeUpdate(sql);
            }
        } finally {
            destroyed();
        }
    }

    private Connection getConnection() throws ClassNotFoundException, SQLException {
        if (null == connection) connection = getConnection(dbFilePath);
        return connection;
    }

    private Statement getStatement() throws SQLException, ClassNotFoundException {
        if (null == statement) statement = getConnection().createStatement();
        return statement;
    }

    /**
     * 数据库资源关闭和释放
     */
    public void destroyed() {
        try {
            if (null != connection) {
                connection.close();
                connection = null;
            }

            if (null != statement) {
                statement.close();
                statement = null;
            }

            if (null != resultSet) {
                resultSet.close();
                resultSet = null;
            }
        } catch (SQLException e) {
            logger.error("Sqlite数据库关闭时异常", e);
        }
    }
}

public interface ResultSetExtractor<T> {
    public abstract T extractData(ResultSet rs);
}

public interface RowMapper<T> {
    public abstract T mapRow(ResultSet rs, int index) throws SQLException;
}

And here's my database factory class, haha:

package cn.deali.utils;

import cn.deali.utils.sqlite.SQLiteHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Database {
    private final static Logger logger = LoggerFactory.getLogger(Database.class);
    private static SQLiteHelper db;
    public static boolean eraseData = false;

    public static SQLiteHelper getInstance() {
        if (db != null)
            return db;

        try {
            db = new SQLiteHelper("test.db");
            return db;
        } catch (Exception ex) {
            logger.error(ex.getMessage());
            return null;
        }
    }

    public static boolean init() {
        logger.info("初始化数据库!");
        db = getInstance();
        try {
            if (eraseData) {
                db.executeUpdate("drop table if exists user;");
                db.executeUpdate("create table user(username varchar(20), password varchar(20));");
                logger.info("创建数据表");
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            logger.error(e.getMessage());
            return false;
        }
    }
}

Pitfalls

First, the Tomcat server has a garbled console output problem on Windows, which is quite annoying. To fix it, you can refer to:

Full Code

Finally, here's the GitHub link. Feel free to grab it if you need it. There's not much technical substance—just a little record.

Link: https://github.com/Deali-Axy/SillyStruts2

Let's Chat

If you have questions, please leave a message on the WeChat official account backend. I'll reply to every message~

_EOF_

My First Experience Using the Struts2 Framework for Web Development in 2020

本文作者:
程序设计实验室
版权声明:
本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!

相关文章

Spring-Boot:创建第一个应用

简介 Spring Boot 是一个轻量级框架,可以完成基于 Spring 的应用程序的大部分配置工作。在本教程中,将学习如何使用 Spring Boot 的 starter、特性和可执行 JAR 文件结构,快速创建能直接运行的基于 Spring 的应用程序。 本文使用IDEA作为开发工具,Gradle作为构建工具,创建一个简单的SpringBoot应用,暂时不涉及数据库的配置。 使用IDEA创建

2022-05-27 · Java · 约 1 分钟

Java开发:JDK安装和环境配置

前言 环境配置是开发中最基础的部分,不过最近有很多新入坑的同学,都在问怎么安装JDK和配置环境,索性写一篇。 这里要注意一下,在Windows平台和Linux平台下做开发是不同的,Windows平台开发Java需要自己手动配置JDK的环境变量,而大多数Linux都是不需要的,安装了OpenJDK就可以了(可能很多发行版都自带了OpenJDK),这点是比较方便的。 下载Java JDK Window

2023-02-08 · Java · 约 1 分钟

在Linux-Ubuntu上配置开发JavaFx程序-(更新)

前言 不清楚什么原因,网络上关于JavaFx的中文资料很少,并且都很老,所以建议大家有兴趣学习JavaFx还是看官方文档比较好,而且貌似部分人不看好JavaFx。 关于Swing的资料倒是要多很多。我觉得挺奇怪的,从设计上来将,还是JavaFx高明一些嘛。 PS:经过近一周的折腾和探索,发现OpenJDK使用JavaFX真的好多坑~ OpenJDK 和 Oracle JDK的配置是有差别的,这里推

2022-05-27 · Java · 约 1 分钟

讨论

共 0 条

良言一句三冬暖,恶语伤人六月寒。

加载评论中…