SliiyStruts2

又名 sb-struts2,因为struts真的太难用了(也许在很多年前是很好用的,但是现在看来,被其他框架秒成渣)

前言

想不到我还是得和这struts框架打交道啊,从一开始学web的时候就十分抵制这类古老,使用反人类的框架,不过为了帮女朋友做个学校的作业,还是得搞一下,然而,半小时就写好的业务代码,因为我不熟悉这个框架和Java的这套体系,调试了半天才成功run起来……(心好累)

开始

首先使用idea创建struts2项目,但是坑来了,idea创建的少了一个包,请自行去maven仓库下载,具体是少了这个包

javassist-3.26.0-GA.jar

接着就可以开始写代码了……

关于Struts2框架的学习参考:

这篇写得很好,很详细,里面还有例子,跟着做就可以自己实现一个简单的struts框架了……

配置

先写一个最简单的IndexAction,这里主要是做数据库的初始化工作,代码如下:

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;
    }
}

写完了Action之后还要给一个配套的jsp页面,这叫做MVC设计模式,前后端分离(伪)……

<%--
  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>

其他的代码由于篇幅关系我就没放上来,本文最后有GitHub地址,有需要可以参考

之后就可以配置struts2了,就像这样……

<?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>

其中的<default-action-ref name="Index"/>是我后来学到的,默认action,一开始我以为和其他框架一样,定义一个“/”路由就可以了,结果自己坑了自己,调试了半天都不行。

参考资料:

日志记录

一开始用的是log4j,感觉有点坑啊,然后想起来之前用过slf4j,虽然两个不是同个概念的,不过slf4j+slf4j-simple,是真的好用,方便,(ps:需要性能更好的可以用logback,hhh),log4j配置真的麻烦,而且嵌入到tomcat服务器,反正我这只是做个作业,不用搞太麻烦。

而且slf4j的输出模板也很好用,至少不会像log4j那么麻烦要拼接字符串了。

关于日志记录的操作参考:

关于我自己的Log4J的配置我这也放上来吧,虽然最后没用上。

# 配置根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

数据库

数据库又是喜闻乐见的SQLite了,反正每次我都是用这个,hhh……

关于Java使用SQLite,可以参考:

附上我的SQLiteHelper实用类代码:

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;
}

还有我的数据库工厂类,哈哈:

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;
        }
    }
}

首先是tomcat服务器在Windows上有控制台输出乱码的问题,很烦,解决的话可以参考:

完整代码

最后附上GitHub地址,有需要自取,没啥技术含量,就是做个小记录。

地址: https://github.com/Deali-Axy/SillyStruts2

欢迎交流

交流问题请在微信公众号后台留言,每一条信息我都会回复哈~ - 微信公众号:画星星高手 - 打代码直播间:https://live.bilibili.com/11883038 - 知乎:https://www.zhihu.com/people/dealiaxy - 简书:https://www.jianshu.com/u/965b95853b9f