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...
目录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:
-
Detailed Explanation of Log4j.properties Configuration with Examples - 简约人生's Blog - CSDN Blog
-
Java Logging Frameworks: The Role of slf4j and Its Implementation Principles
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:
- Fixing garbled Tomcat console output
- Tomcat encoding issue: setting catalina.bat to UTF-8 causes garbled console output
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~
- WeChat official account: 画星星高手
- Coding livestream: https://live.bilibili.com/11883038
- Zhihu: https://www.zhihu.com/people/dealiaxy
- Jianshu: https://www.jianshu.com/u/965b95853b9f
_EOF_
My First Experience Using the Struts2 Framework for Web Development in 2020
- 本文作者:
- 程序设计实验室
- 版权声明:
- 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
相关文章
Java使用JDBC操作SQLite
SQLite介紹 SQLite是一個輕量級的資料庫系統,不需要安裝就可以使用,也可以十分容易的就內嵌於系統內,FireFox就內嵌SQLite,可以在FireFox上直接使用JavaScript來呼叫操作資料庫。 SQLite是由C語言撰寫而已,可以跨Linux及Windows等平台,在Java存取及操作上則可使用JDBC來連線SQLite。 在JDBC連線SQLite上,大概分成二種方式,一種是
2021-12-18 · Java · 约 1 分钟
JavaWeb开发---使用IDEA创建Servlet程序
前言 最近做项目需要,从之前熟悉的PHP和Python转到了JavaWeb,所以就有了这个笔记。资源图片都是来自网上的资源,根据自己的实际操作应用,做了总结归纳。 所需工具 JDK Tomcat IDEA 创建工程 设置工程名字: 创建完成后工程结构如下: 上面的图片是在网络上复制的,好像我用的IDEA 2017.3.2没有这个Create web.xml的选项,我也不知道为啥,难道是IDEA越更
2021-12-18 · Java · 约 1 分钟
深入Jar包:Gradle构建可执行jar包与访问jar包中文件夹与文件
前言 Java的跨平台功能听起来很诱人可口,号称“Write Once,Run Everywhere”,实际上是“Run Once,Debug Everywhere”... 在实际开发过程中还是会遇到各种各样的坑的,刚刚解决了一系列问题,特地写个文章总结一下。 使用Gradle构建Jar包 感谢万能的Gradle,极大提高了Java开发的生产力~ 在Gradle中生成jar包可以使用官方的插件:a
2022-05-27 · Java · 约 1 分钟
JavaWeb开发---Servlet的生命周期实验
前言 Servlet是运行在服务器端的程序,它的运行状态由Servlet容器(简称容器)来维护。 通常,在容器收到客户对Servlet的请求时,容器会判断这个Servlet是否为第一次被访问,如果是第一次被访问,则会创建一个Servlet实例同时调用该实例的init()方法,进行初始化。 每个Servlet只会被创建一个实例,同时也只会被初始化一次。然后将这个实例一直保存在内存中,对所有的请求进行
2022-05-27 · Java · 约 1 分钟
讨论
共 0 条加载评论中…