软件构造实验三——调用JFinal框架实现增删改查的学生信息管理系统

发布时间 2023-12-27 18:13:41作者: yesyes1

项目结构

具体代码

_JFinalDemoGenerator.java

package org.example.common.model;

import com.jfinal.plugin.activerecord.dialect.MysqlDialect;
import com.jfinal.plugin.activerecord.generator.Generator;
import com.jfinal.plugin.activerecord.generator.TypeMapping;
import com.jfinal.plugin.druid.DruidPlugin;
import org.example.common.DemoConfig;

import javax.sql.DataSource;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Date;

public class _JFinalDemoGenerator {
    public static DataSource getDataSource(){
        DruidPlugin druidPlugin= DemoConfig.createDruidPlugins();
        druidPlugin.start();
        return druidPlugin.getDataSource();
    }

    public static void main(String[] args) {
        String modelPackageName="org.example.common.model";

        String baseModelPackageName=modelPackageName+".base";

        String baseModelOutputDir = System.getProperty("user.dir")
                + "/src/main/java/" + baseModelPackageName.replace('.', '/');

        System.out.println("输出路径:"+ baseModelOutputDir);

        // model 文件保存路径 (MappingKit 与 DataDictionary 文件默认保存路径)
        String modelOutputDir = baseModelOutputDir + "/..";

        // 创建生成器
        Generator generator = new Generator(getDataSource(), baseModelPackageName, baseModelOutputDir, modelPackageName, modelOutputDir);

        // 配置是否生成备注
        generator.setGenerateRemarks(true);

        // 设置数据库方言
        generator.setDialect(new MysqlDialect());

        // 设置是否生成链式 setter 方法,强烈建议配置成 false,否则 fastjson 反序列化会跳过有返回值的 setter 方法
        generator.setGenerateChainSetter(false);

        // 添加不需要生成的表名到黑名单
        generator.addBlacklist("adv");

        // 设置是否在 Model 中生成 dao 对象
        generator.setGenerateDaoInModel(false);

        // 设置是否生成字典文件
        generator.setGenerateDataDictionary(false);

        // 设置需要被移除的表名前缀用于生成modelName。例如表名 "osc_user",移除前缀 "osc_"后生成的model名为 "User"而非 OscUser
        generator.setRemovedTableNamePrefixes("t_");

        // 将 mysql 8 以及其它原因之下生成 jdk 8 日期类型映射为 java.util.Date,便于兼容老项目,也便于习惯使用 java.util.Date 的同学
        TypeMapping tm = new TypeMapping();
        tm.addMapping(LocalDateTime.class, Date.class);
        tm.addMapping(LocalDate.class, Date.class);
        // tm.addMapping(LocalTime.class, LocalTime.class);		// LocalTime 暂时不变
        generator.setTypeMapping(tm);

        // 生成
        generator.generate();
    }
}

_MappingKit.java

package org.example.common.model;

import com.jfinal.plugin.activerecord.ActiveRecordPlugin;

public class _MappingKit {
    public static void mapping(ActiveRecordPlugin activeRecordPlugin){
        activeRecordPlugin.addMapping("jfinalstudent","id", Student.class);
    }
}

Student.java

package org.example.common.model;

import com.jfinal.plugin.activerecord.Model;
import org.example.common.model.base.BaseStudent;

public class Student extends BaseStudent<Student> {
}

DemoConfig.java

package org.example.common;

import com.jfinal.config.*;
import com.jfinal.kit.Prop;
import com.jfinal.kit.PropKit;
import com.jfinal.plugin.activerecord.ActiveRecordPlugin;
import com.jfinal.plugin.druid.DruidPlugin;
import com.jfinal.server.undertow.UndertowServer;
import com.jfinal.template.Engine;
import org.example.common.model._MappingKit;

public class DemoConfig extends JFinalConfig {

    static Prop p;

    //项目的启动类函数
    public static void main(String[] args) {
        UndertowServer.start(DemoConfig.class);
    }

    //寻找配置文件的配置函数方法
    static void loadConfig(){
        if(p==null){
            p= PropKit.useFirstFound("demo-config-pro.txt","demo-config-dev.txt");
        }
    }

    @Override
    public void configConstant(Constants constants) {
        loadConfig();

        constants.setDevMode(p.getBoolean("devMode",false));

        constants.setInjectDependency(true);

        constants.setInjectSuperClass(true);
    }

    @Override
    public void configRoute(Routes routes) {
        routes.scan("org.example.");
    }

    @Override
    public void configEngine(Engine engine) {
        engine.addSharedFunction("/common/_layout.html");
        engine.addSharedFunction("/common/_paginate.html");
    }

    @Override
    public void configPlugin(Plugins plugins) {
        DruidPlugin druidPlugin=new DruidPlugin(p.get("jdbcUrl"),p.get("user"),p.get("password"));
        plugins.add(druidPlugin);

        ActiveRecordPlugin activeRecordPlugin=new ActiveRecordPlugin(druidPlugin);
        _MappingKit.mapping(activeRecordPlugin);
        plugins.add(activeRecordPlugin);
    }

    public static DruidPlugin createDruidPlugins(){
        loadConfig();

        return new DruidPlugin(p.get("jdbcUrl"),p.get("user"),p.get("password"));
    }


    @Override
    public void configInterceptor(Interceptors interceptors) {

    }

    @Override
    public void configHandler(Handlers handlers) {

    }
}

StudentController.java

package org.example.Student;

import com.jfinal.aop.Before;
import com.jfinal.aop.Inject;
import com.jfinal.core.Controller;
import com.jfinal.core.Path;
import org.example.common.model.Student;

@Path("/student")
@Before(StudentInterceptor.class)
public class StudentController extends Controller {
    @Inject
    StudentService studentService;

    public void index(){
        setAttr("studentPage",
                studentService.paginate(getParaToInt(0,1),10));
        render("student.html");
    }

    public void add(){

    }

    @Before(StudentValidator.class)
    public void save(){
        getBean(Student.class).save();
        redirect("/student");
    }

    public void edit(){
        setAttr("student",studentService.findById(getParaToInt()));
    }

    @Before(StudentValidator.class)
    public void update(){
        getBean(Student.class).update();
        redirect("/student");
    }

    public void delete(){
        studentService.deleteById(getParaToInt());
        redirect("/student");
    }

    public void check(){
        int id=Integer.parseInt(getPara("id"));
        System.out.println("id   "+id);
        Student student=studentService.findById(id);
        System.out.println("student  "+student);
        setAttr("student",student);
        render("one.html");
    }
}

StudentInterceptor.java

package org.example.Student;

import com.jfinal.aop.Interceptor;
import com.jfinal.aop.Invocation;

public class StudentInterceptor implements Interceptor {
    @Override
    public void intercept(Invocation invocation) {
        System.out.println("Before invoking:"+invocation.getActionKey());
        invocation.invoke();
        System.out.println("After invoking:"+invocation.getActionKey());
    }
}

StudentService.java

package org.example.Student;

import com.jfinal.plugin.activerecord.Page;
import org.example.common.model.Student;

public class StudentService {
    private Student dao=new Student().dao();

    public Page<Student> paginate(int pageNumber,int pageSize){
        return dao.paginate(pageNumber,pageSize,"select *","from jfinalstudent order by id asc");
    }

    public Student findById(int id){
        return dao.findById(id);
    }

    public void deleteById(int id){
        dao.deleteById(id);
    }
}

StudentValidator.java

package org.example.Student;

import com.jfinal.core.Controller;
import com.jfinal.validate.Validator;
import org.example.common.model.Student;

public class StudentValidator extends Validator {
    @Override
    protected void validate(Controller controller) {
        validateRequiredString("student.name","nameMsg","请输入学生姓名");
        validateRequiredString("student.age","ageMsg","请输入学生年龄");
        validateRequiredString("student.grade","gradeMsg","请输入学生年级");
    }

    @Override
    protected void handleError(Controller controller) {
        controller.keepModel(Student.class);

        String actionKey=getActionKey();
        if(actionKey.equals("/student/save")){
            controller.render("add.html");
        }else if(actionKey.equals("/student/update")){
            controller.render("edit.html");
        }
    }
}

demo-config-dev.txt

# config
jdbcUrl = jdbc:mysql://localhost/数据库名称?characterEncoding=utf8&useSSL=false&zeroDateTimeBehavior=convertToNull
user = 用户名
password = 数据库密码
devMode = true

log4j.properties

# log4j.rootLogger=WARN, stdout, file
log4j.rootLogger=WARN, stdout, file
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%n%-d{yyyy-MM-dd HH:mm:ss}%n[%p]-[Thread: %t]-[%C.%M()]: %m%n

# Output to the File
log4j.appender.file=org.apache.log4j.DailyRollingFileAppender
log4j.appender.file.DatePattern='_'yyyy-MM-dd'.log'
log4j.appender.file.File=./log/jfinal_demo_for_maven.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%n%-d{yyyy-MM-dd HH:mm:ss}%n[%p]-[Thread: %t]-[%C.%M()]: %m%n

logging.properties


# 下载地址:
# https://github.com/undertow-io/undertow/blob/master/examples/src/main/resources/logging.properties

#
# JBoss, Home of Professional Open Source.
# Copyright 2012 Red Hat, Inc., and individual contributors
# as indicated by the @author tags.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

# Additional logger names to configure (root logger is always configured)
loggers=org.xnio.listener,org.xnio.ssl,org.apache,io.undertow.util.TestHttpClient

# Root logger configuration
logger.level=${test.level:ERROR}
logger.handlers=CONSOLE

# Console handler configuration
handler.CONSOLE=org.jboss.logmanager.handlers.ConsoleHandler
handler.CONSOLE.properties=autoFlush,target
handler.CONSOLE.target=SYSTEM_ERR
handler.CONSOLE.level=ALL
handler.CONSOLE.autoFlush=true
handler.CONSOLE.formatter=PATTERN

# The log format pattern
formatter.PATTERN=org.jboss.logmanager.formatters.PatternFormatter
formatter.PATTERN.properties=pattern
formatter.PATTERN.pattern=%d{HH:mm:ss,SSS} %-5p (%t) [%c] <%F:%L> %m%n

logger.org.xnio.listener.level=DEBUG

logger.org.xnio.ssl.level=DEBUG

logger.org.apache.level=WARN
logger.org.apache.useParentHandlers=false
logger.io.undertow.util.TestHttpClient.level=WARN

_layout.html

#define layout()
<!DOCTYPE HTML PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xml:lang="zh-CN" xmlns="http://www.w3.org/1999/xhtml" lang="zh-CN">
<head>
    <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
    <link media="screen" rel="stylesheet" type="text/css" />
    <script type="text/javascript" ></script>
</head>
<body>
<div class="manage_container">
<!--    <div class="manage_head">-->
<!--        <div class="manage_logo">-->
<!--            <a href="https://jfinal.com" target="_blank">学生信息管理系统</a>-->
<!--        </div>-->
<!--        <div id="nav">-->
<!--            <ul>-->
<!--                <li><a href="/student"><b>学生信息管理</b></a></li>-->
<!--            </ul>-->
<!--        </div>-->
<!--    </div>-->
    <div class="main">
        #@main()
    </div>
</div>
</body>
</html>
#end

_paginate.html

#define paginate(currentPage, totalPage, link)
#if(totalPage <= 0 || currentPage > totalPage) #return #end
#setLocal(startPage = currentPage - 4)
#if (startPage < 1) #setLocal(startPage = 1) #end

#setLocal(endPage = currentPage + 4)
#if (endPage > totalPage) #setLocal(endPage = totalPage) #end

<div class="pagination">
    #if (currentPage <= 8)
    #setLocal(startPage = 1)
    #end
    #if ((totalPage - currentPage) < 8)
    #setLocal(endPage = totalPage)
    #end

    #if (currentPage == 1)
    <span class="disabled prev_page">上页</span>
    #else
    <a href="#(link)#(currentPage - 1)#(append)" class="prev_page">上页</a>
    #end

    #if (currentPage > 8)
    <a href="#(link)#(1)#(append)">#(1)</a>
    <a href="#(link)#(2)#(append)">#(2)</a>
    <span class="gap">…</span>
    #end

    #for(i : [startPage..endPage])
    #if (currentPage == i)
    <span class="current">#(i)</span>
    #else
    <a href="#(link)#(i)#(append)">#(i)</a>
    #end
    #end

    #if ((totalPage - currentPage) >= 8)
    <span class="gap">…</span>
    <a href="#(link)#(totalPage - 1)#(append)">#(totalPage - 1)</a>
    <a href="#(link)#(totalPage)#(append)">#(totalPage)</a>
    #end

    #if (currentPage == totalPage)
    <span class="disabled next_page">下页</span>
    #else
    <a href="#(link)#(currentPage + 1)#(append)" class="next_page" rel="next">下页</a>
    #end
</div>
#end

_form.html

<center>
  <fieldset class="solid">
    <legend>学生信息管理</legend>
    <table>
      <tr>
        <td>
          <input type="hidden" name="student.id" value="#(student.id??)" />
        </td>
      </tr>
      <tr>
        <td>
          <div>
            <label>姓名</label>
            <input type="text" name="student.name" value="#(student.name??)" />#(nameMsg)
          </div>
        </td>
      </tr>
      <tr>
        <td>
          <div>
            <label>年龄</label>
            <input type="text" name="student.age" value="#(student.age??)"/>#(ageMsg)
          </div>
        </td>
      </tr>
      <tr>
        <td>
          <div>
            <label>年级</label>
            <input type="text" name="student.grade" value="#(student.grade??)"/>#(gradeMsg)
          </div>
        </td>
      </tr>
      <tr>
        <td>
          <div>
            <label>&nbsp;</label>
            <input value="提交" type="submit">
          </div>
        </td>
      </tr>
    </table>
  </fieldset>
</center>

add.html

#@layout()
#define main()
<h1>添加学生信息
</h1>
<div class="form_box">
  <form action="/student/save" method="post">
    #include("_form.html")
  </form>
</div>
#end

edit.html

#@layout()
#define main()
<h1>修改学生信息
</h1>
<div class="form_box">
    <form action="/student/update" method="post">
        #include("_form.html")
    </form>
</div>
#end

one.html

#@layout()
#define main()
<h1>学生详细信息
</h1>

<center>
  <a href="/student">浏览全部信息</a>
<div class="form_box">
  <table>
    <tr>
      <td>学号:</td>
      <td>#(student.id)</td>
    </tr>
    <tr>
      <td>姓名:</td>
      <td>#(student.name)</td>
    </tr>
    <tr>
      <td>年龄:</td>
      <td>#(student.age)</td>
    </tr>
    <tr>
      <td>年级:</td>
      <td>#(student.grade)</td>
    </tr>
  </table>
</div>
</center>
#end

student.html

#@layout()
#define main()
<center>
  <h1>
    <a href="/student/add">添加学生信息</a>
  </h1>
  <form action="/student/check" method="post">
    <table>
      <tr>
        <td>
          <input type="text" name="id" placeholder="请根据学生编号进行查询">
          <input type="submit" value="查询">
        </td>
      </tr>
    </table>
  </form>
</center>
<div class="table_box">
  <table class="list" border="1" align="center">
    <tbody>
    <tr>
      <th width="4%">学号</th>
      <th width="10%">姓名</th>
      <th width="10%">年龄</th>
      <th width="20%">年级</th>
      <th width="12%">操作</th>
    </tr>

    #for(x : studentPage.getList())
    <tr align="center">
      <td width="4%">#(x.id)</td>
      <td width="10%">#(x.name)</td>
      <td width="10%">#(x.age)</td>
      <td width="20%">#(x.grade)</td>
      <td width="12%">
        &nbsp;&nbsp;<a href="/student/delete/#(x.id)">删除</a>
        &nbsp;&nbsp;<a href="/student/edit/#(x.id)">修改</a>
      </td>
    </tr>
    #end
    </tbody>
  </table>
</div>
#end

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>jfinal-web</artifactId>
    <version>1.0-SNAPSHOT</version>

    <repositories>
        <repository>
            <id>ali-maven</id>
            <url>http://maven.aliyun.com/nexus/content/groups/public</url>
            <releases>
                <enabled>true</enabled>
            </releases>
            <snapshots>
                <enabled>true</enabled>
                <updatePolicy>always</updatePolicy>
                <checksumPolicy>fail</checksumPolicy>
            </snapshots>
        </repository>
    </repositories>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>

        <!-- jfinal -->
        <dependency>
            <groupId>com.jfinal</groupId>
            <artifactId>jfinal</artifactId>
            <version>5.0.0</version>
        </dependency>

        <!-- jfinal-undertow 开发、部署一体化 web 服务器 -->
        <dependency>
            <groupId>com.jfinal</groupId>
            <artifactId>jfinal-undertow</artifactId>
            <version>3.0</version>
        </dependency>

        <!-- cos 文件上传 -->
        <dependency>
            <groupId>com.jfinal</groupId>
            <artifactId>cos</artifactId>
            <version>2022.2</version>
        </dependency>

        <!-- junit 单元测试 -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.2</version>
            <scope>test</scope>
        </dependency>

        <!-- 避免控制台输出如下提示信息:
             SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
             项目中实际上用不到这个 jar 包,本 jfinal demo 用不上这个依赖,在此仅为大家
             在未来基于 jfinal demo 为模板做开发时做准备工作
             注意:eclipse 下可以将 scope 设置为 provided
        -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-nop</artifactId>
            <version>1.7.29</version>
            <!-- 打包前改成 provided,此处使用 compile 仅为支持 IDEA -->
            <scope>compile</scope>
        </dependency>

        <!-- log4j 日志 -->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>

        <!-- mysql 驱动 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.49</version>
        </dependency>

        <!-- druid 数据源连接池 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.0.29</version>
        </dependency>

    </dependencies>

<build>
    <!--
		    添加 includes 配置后,excludes 默认为所有文件 **/*.*,反之亦然
		    该规则在 maven-jar-plugin 等插件中同样适用
		-->
    <resources>
        <!-- 添加该配置是为了将 .sql 文件打入 jar 包 -->
        <resource>
            <directory>src/main/java</directory>
            <includes>
                <!-- **/* 前缀用法,可以匹配所有路径 -->
                <include>**/*.sql</include>
            </includes>
        </resource>

        <!--
            没有添加 resources 配置时,src/main/resources 目录是默认配置
            一旦添加 resources 配置指向 src/main/java 目录时,原先的默认配置被取代,
            所以需要添加如下配置将默认配置再添加进来,否则无法使用 src/main/resources
            下的资源文件
        -->
        <resource>
            <directory>src/main/resources</directory>
        </resource>
    </resources>



    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.6.1</version>
            <configuration>
                <source>1.8</source>
                <target>1.8</target>
                <encoding>UTF-8</encoding>
                <!-- java8 保留参数名编译参数 -->
                <compilerArgument>-parameters</compilerArgument>
                <compilerArguments><verbose /></compilerArguments>
            </configuration>
        </plugin>

        <!--
            jar 包中的配置文件优先级高于 config 目录下的 "同名文件"
            因此,打包时需要排除掉 jar 包中来自 src/main/resources 目录的
            配置文件,否则部署时 config 目录中的同名配置文件不会生效
         -->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-jar-plugin</artifactId>
            <version>2.6</version>
            <configuration>
                <excludes>
                    <!--
                         *.* 用法,可以匹配 jar 包根目录下所有文件
                         *.xxx 用法,可以匹配 jar 包根目录下特定扩展名文件,例如:*.xml
                         **/* 前缀用法,可以匹配所有路径,例如:**/*.txt
                         / 后缀用法,表示排除目录,例如:pro/
                         普通字符串用法,表示排除特定文件,例如: filename
                    -->
                    <exclude>*.*</exclude>
                    <exclude>pro/</exclude>
                    <exclude>dev/</exclude>
                    <exclude>filename</exclude>
                </excludes>
            </configuration>
        </plugin>

        <!--
            使用 mvn clean package 打包
            更多配置可参考官方文档:http://maven.apache.org/plugins/maven-assembly-plugin/single-mojo.html
         -->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-assembly-plugin</artifactId>
            <version>3.1.0</version>
            <executions>
                <execution>
                    <id>make-assembly</id>
                    <phase>package</phase>
                    <goals>
                        <goal>single</goal>
                    </goals>

                    <configuration>
                        <!-- 打包生成的文件名 -->
                        <finalName>${project.artifactId}</finalName>
                        <!-- jar 等压缩文件在被打包进入 zip、tar.gz 时是否压缩,设置为 false 可加快打包速度 -->
                        <recompressZippedFiles>false</recompressZippedFiles>
                        <!-- 打包生成的文件是否要追加 package.xml 中定义的 id 值 -->
                        <appendAssemblyId>true</appendAssemblyId>
                        <!-- 指向打包描述文件 package.xml -->
                        <descriptors>
                            <descriptor>package.xml</descriptor>
                        </descriptors>
                        <!-- 打包结果输出的基础目录 -->
                        <outputDirectory>${project.build.directory}/</outputDirectory>
                    </configuration>
                </execution>
            </executions>
        </plugin>

    </plugins>
</build>

</project>