JFinal与JavaWeb对比总结
来源:互联网 发布:信信通是正规软件吗 编辑:程序博客网 时间:2024/06/06 13:07
分别创建两个maven-archetype-webapp项目。将分别其命名为javaweb_maven与jfinal_maven。在Javaweb_maven项目中,通过maven引入servlet(servlet和jsp的使用)、junit(单元测试)、mysql(数据库引擎)、jstl(JSP标准标签库)和taglibs(JSP标准标签库)。
在JFinal项目中,通过maven引入上面项目中所需要引入的所有外,需要额外引入jfinal(JFinal的使用)。
web.xml版本为3.0。
使用JFinal前需要先创建一个继承JFinalConfig的类(以下简称Config类),然后开始配置web.xml文件,在其中加上
<filter><filter-name>jfinal</filter-name><filter-class>com.jfinal.core.JFinalFilter</filter-class><init-param><param-name>configClass</param-name><param-value>config.Config</param-value></init-param></filter><filter-mapping><filter-name>jfinal</filter-name><url-pattern>/*</url-pattern></filter-mapping>
其中<param-value></param-value>项中填Config类的路径,<param-name></param-name>项中填继承Config类的名称。
一、连接数据库
事先准备:创建一个数据库配置文件:dbconfig.properties,里面写入数据库用到的各项配置,如:url,username,password,driverClass。然后将该文件复制两份放入两个项目的src/main/resources中。(注:放入两个项目中的该配置文件中的url后面的数据库名是不同的,记得修改。)
例,其中jfinal_test的dbconfig.properties文件代码:
driver=com.mysql.jdbc.Driverurl=jdbc:mysql://localhost:20001/jfinal_testuser=rootpassword=123456
1、JavaWeb
在JavaWeb中,我建立了一个DBCon类,放在jdbc包下,用来连接数据库,获取连接完数据库的Connection对象(后续与数据库相关操作都是通过Connection对象进行)。
在该类中,我定义了4个私有静态变量,并定义了一个静态块用来从数据库配置文件中读取出来的各项值,然后赋值给那4个私有变量。
private static String DB_DRIVER;private static String DB_URL;private static String DB_USERNAME;private static String DB_PASSWORD;static{Properties p = new Properties();InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream("dbconfig.properties");try {p.load(is);DB_DRIVER = p.getProperty("driver");DB_URL = p.getProperty("url");DB_USERNAME = p.getProperty("user");DB_PASSWORD = p.getProperty("password");} catch (IOException e) {e.printStackTrace();}}
在该类中,还定义了一个静态方法,用来获取Connection对象。
private static Connection connection;public static Connection GetConnection(){if (connection == null) { try { Class.forName(DB_DRIVER); } catch (ClassNotFoundException e) { e.printStackTrace(); } try { connection = DriverManager.getConnection(DB_URL, DB_USERNAME, DB_PASSWORD); } catch (SQLException e) { e.printStackTrace(); }}return connection;}
之后其他类,就可以通过DBCon.GetConnection()来获取与数据库的连接对象了。
为了验证该方法是否正确,使用JUnit创建一个测试类DBConTest。里面添加一个测试方法testGetConnection,用来测试是否能成功获取数据库连接。
@Test public void testGetConnection() { Connection conn = DBCon.GetConnection(); try { assertNotNull(conn.createStatement().executeQuery("select * from commodity")); } catch (SQLException e) { e.printStackTrace(); } }
测试通过,说明该方法可以成功获取数据库的连接。(数据库里已经有表格,没有数据也能测试通过)
2、JFinal
在Config类中的configConstant方法中,使用loadPropertyFile方法获取数据库配置文件,这样方便之后再其他地方的调用。(me.setDevMode(true),是由于当前未开发版本,设置这个可以使得JFinal会对每次请求输出报告,如输出本次请求的URL、Controller、Method以及请求所携带的参数。)
@Override public void configConstant(Constants me) { loadPropertyFile("dbconfig.properties"); me.setDevMode(true); }
设置完configConstant方法后,在Config类中的configPlugin方法里配置数据库的连接。
@Override public void configPlugin(Plugins me) { DruidPlugin dp = new DruidPlugin(getProperty("url"), getProperty("user"), getProperty("password"), getProperty("driver")); me.add(dp); ActiveRecordPlugin arp = new ActiveRecordPlugin(dp); me.add(arp); arp.addMapping("commodity", Commodity.class); arp.addMapping("account", Account.class); }
其中getProperty方法,读取的便是之前loadPropertyFile加载的配置文件中的相应键对应的值。如果存在重复的键值对,则取最后出现的键值对的值。
其中的arp.addMapping("commodity", Commodity.class)与arp.addMapping("account", Account.class),是完成了数据库表格与项目model的映射。Commodity.class与Account.class是在项目中创建的继承自Model<Commodity>与Model<Account>的类。
其中的DruidPlugin 类,这是一个数据源插件,可以使用jfinal自带的com.jfinal.plugin.druid.DruidPlugin类,不过需要在Maven中引入alibaba的druid项目,然后通过调用其构造函数,输入url、username、password和driver的值即可。除了使用jfinal自带的com.jfinal.plugin.druid.DruidPlugin类,还可以使用自定义的类,只需要实现com.jfinal.plugin.IPlugin接口和com.jfinal.plugin.activerecord.IDataSourceProvider接口即可,这样便无需在Maven中额外引入druid。
接下来是ActiveRecordPlugin这个类。其定义了一个接受IDataSourceProvider类型的构造器:
public ActiveRecordPlugin(IDataSourceProvider dataSourceProvider) { this(DbKit.MAIN_CONFIG_NAME, dataSourceProvider); }
this(DbKit.MAIN_CONFIG_NAME, dataSourceProvider)这段代码读取了一个重载的构造器,跟踪进去后发现,那个构造器又调用了一个新的重载的构造器。下面为新的重载的构造器:
public ActiveRecordPlugin(String configName, IDataSourceProvider dataSourceProvider, int transactionLevel) {if (StrKit.isBlank(configName)) {throw new IllegalArgumentException("configName can not be blank");}if (dataSourceProvider == null) {throw new IllegalArgumentException("dataSourceProvider can not be null");}this.dataSourceProvider = dataSourceProvider;this.config = new Config(configName, null, transactionLevel);}
此时,ActiveRecordPlugin的static变量的dataSourceProvider,就已经被赋为之前传入进来的实现了IDataSourceProvider接口的类型的实例了。
接下来看数据库到项目的映射的方法:
arp.addMapping("commodity", Commodity.class);
其中Commodity.class为:
public class Commodity extends Model<Commodity> { private static final long serialVersionUID = -839562708492767863L; public static final Commodity dao = new Commodity().dao(); }
其中声明的dao静态对象是为了方便查询操作而定义的,该对象并不是必须的。
回到ActiveRecordPlugin中,查看其是如何完成映射的。查看源码,我们可以发现,在ActiveRecordPlugin中,定义了两个addMapping方法:
public ActiveRecordPlugin addMapping(String tableName, String primaryKey, Class<? extends Model<?>> modelClass) {tableList.add(new Table(tableName, primaryKey, modelClass));return this;}public ActiveRecordPlugin addMapping(String tableName, Class<? extends Model<?>> modelClass) {tableList.add(new Table(tableName, modelClass));return this;}
一个的参数中需要primaryKey,一个的参数中不需要primaryKey。在继续进入Table类中,查看调用的两个构造器有什么不同。
进去后可以发现,有primaryKey参数的构造器中,比没有primaryKey参数的构造器多使用了一个setPrimaryKey(primaryKey.trim())方法。而setPrimaryKey的方法具体内容如下:
void setPrimaryKey(String primaryKey) {String[] arr = primaryKey.split(",");for (int i=0; i<arr.length; i++)arr[i] = arr[i].trim();this.primaryKey = arr;}
由此可知,是将传入的字符串,按“,”分割,去除空格后,将这个数组赋值给primaryKey。如果没有传入primaryKey的情况下,primaryKey的值默认为id。
因此通过addMapping方法来实现数据库表名到Model的映射关系的话,如果表的主键名为id的话,直接输入表名和相应的Model的类名即可;如果不是id的话,则需要手动指定。如果一个表有多个id的话,可以通过“,”分割开来。
回到源码中,在知道了如何使用数据库连接的情况下,再来看看具体的实现是如何进行的吧。
首先,我们将这个数据库连接是放在继承自JFinalConfig类的configPlugin方法中的。而这个Config类,我们是要在web.xml中配置的,如下。
<filter><filter-name>jfinal</filter-name><filter-class>com.jfinal.core.JFinalFilter</filter-class><init-param><param-name>configClass</param-name><param-value>config.Config</param-value></init-param></filter><filter-mapping><filter-name>jfinal</filter-name><url-pattern>/*</url-pattern></filter-mapping>
关于web.xml中的filter标签,是表示过滤器,其下方的filter-mapping标签中的<url-pattern>/*</url-pattern>则表明,通向该项目的任何请求,都会先转入该过滤器中,即必须先通过com.jfinal.core.JFinalFilter类。
JFinalFilter类继承自javax.servlet.Filter类。重写了init方法(Filter类的init方法会在服务器启动过程中调用),创建了Config的实例,并且调用了JFinal的init方法。具体代码如下:
private Handler handler;private String encoding;private JFinalConfig jfinalConfig;private Constants constants;private static final JFinal jfinal = JFinal.me();private static Log log;private int contextPathLength;public void init(FilterConfig filterConfig) throws ServletException {createJFinalConfig(filterConfig.getInitParameter("configClass"));if (jfinal.init(jfinalConfig, filterConfig.getServletContext()) == false) {throw new RuntimeException("JFinal init error!");}handler = jfinal.getHandler();constants = Config.getConstants();encoding = constants.getEncoding();jfinalConfig.afterJFinalStart();String contextPath = filterConfig.getServletContext().getContextPath();contextPathLength = (contextPath == null || "/".equals(contextPath) ? 0 : contextPath.length());}
其中的jfinal.init(jfinalConfig, filterConfig.getServletContext(),调用了JFinal的init方法:
boolean init(JFinalConfig jfinalConfig, ServletContext servletContext) {this.servletContext = servletContext;this.contextPath = servletContext.getContextPath();initPathUtil();Config.configJFinal(jfinalConfig);// start plugin, init log factory and init engine in this methodconstants = Config.getConstants();initActionMapping();initHandler();initRender();initOreillyCos();initTokenManager();return true;}
其中的Config.configJFinal(jfinalConfig)是一个关键点,主要是通过Config来加载暴露给程序员的核心文件。点击去看看:
static void configJFinal(JFinalConfig jfinalConfig) {jfinalConfig.configConstant(constants); initLogFactory(); initEngine();jfinalConfig.configRoute(routes);jfinalConfig.configEngine(engine);jfinalConfig.configPlugin(plugins); startPlugins(); // very important!!!jfinalConfig.configInterceptor(interceptors);jfinalConfig.configHandler(handlers);}
注意其中的这一行:
jfinalConfig.configPlugin(plugins); startPlugins(); // very important!!!
这里的startPlugins();并不是注释,而是一个需要执行的方法。
而调用各个configxxxx方法的jfinalConfig对象,则是我们定义的Config对象的一个实例。因此这里的各个configxxxx方法,就是调用我们在Config类中定义的这几个方法。
在startPlugins这个方法中,就遍历了所有添加的Plugin,并分别调用了他们的start方法。这就是整个连接数据库的起始原点了。
而后回到ActiveRecordPlugin类中,查看其start()方法,在ActiveRecordPlugin的start()方法中,又调用了TableBuilder类的build方法。
在build方法中,遍历了添加进来的各个Table对象,并为其建表。并在其中调用了自身的doBuild方法,进行相关映射。源码如下:
private void doBuild(Table table, Connection conn, Config config) throws SQLException {table.setColumnTypeMap(config.containerFactory.getAttrsMap());if (table.getPrimaryKey() == null) {table.setPrimaryKey(config.dialect.getDefaultPrimaryKey());}String sql = config.dialect.forTableBuilderDoBuild(table.getName());Statement stm = conn.createStatement();ResultSet rs = stm.executeQuery(sql);ResultSetMetaData rsmd = rs.getMetaData();for (int i=1; i<=rsmd.getColumnCount(); i++) {String colName = rsmd.getColumnName(i);String colClassName = rsmd.getColumnClassName(i);Class<?> clazz = javaType.getType(colClassName);if (clazz != null) {table.setColumnType(colName, clazz);}else {int type = rsmd.getColumnType(i);if (type == Types.BINARY || type == Types.VARBINARY || type == Types.BLOB) {table.setColumnType(colName, byte[].class);} else if (type == Types.CLOB || type == Types.NCLOB) {table.setColumnType(colName, String.class);} else {table.setColumnType(colName, String.class);}// core.TypeConverter// throw new RuntimeException("You've got new type to mapping. Please add code in " + TableBuilder.class.getName() + ". The ColumnClassName can't be mapped: " + colClassName);}}rs.close();stm.close();}
3、小结
使用方式:
JavaWeb:
需要自己去从头开始写各个部分的代码,读取数据库配置文件,加载数据库驱动,获取数据库连接,之后有操作数据库操作的时候,再来调用这个获取的连接对象。
JFinal:
创建一个继承自JFinalConfig的类,并将其配置在web.xml中的jfinal过滤器中的初始化参数中(这是JFina初始化的操作,没有这一步JFinal将无法调用)。
之后在创建的Config类中的configPlugin方法里进行配置即可,示例代码如下:
@Override public void configPlugin(Plugins me) { loadPropertyFile("dbconfig.properties"); DruidPlugin dp = new DruidPlugin(getProperty("url"), getProperty("user"), getProperty("password"), getProperty("driver")); me.add(dp); ActiveRecordPlugin arp = new ActiveRecordPlugin(dp); me.add(arp); arp.addMapping("commodity", Commodity.class); arp.addMapping("account", Account.class); }
loadPropertyFile方法为读取相应的配置文件,之后可以通过getProperty方法取出配置文件中定义的各项值出来。
DruidPlugin 为数据库连接池插件,JFinal自带,不过需要引入alibaba的druid类库才可以使用。不过也可以不使用DruidPlugin,而使用一个自定义的类,不过需要实现IPlugin,IDataSourceProvider这两个接口。
me.add(IPlugin plugin)方法,添加一个实现了IPlugin接口的类型的对象进入pluginList中,而在项目部署过程中,会遍历pluginList中的所有对象,调用其start()方法。
ActiveRecordPlugin类为初始化数据库表格到项目Model的映射,使用arp.addMapping方法,传入“表格名”和“Model类名”,即可完成映射,不过这样完成的映射,表格的主键必须为id,如果表格的主键不是id,可以通过arp.addMapping(String tableName, String primaryKey, Class<? extends Model<?>> modelClass),即在添加一个String类型的参数位于第二的位置表示主键名即可。
JFinal启动类图示意:
- JFinal与JavaWeb对比总结
- JFinal分页总结
- Hibernate与Mybatis对比总结
- hibernate与mybatis对比总结
- sizeof与strlen对比总结
- JavaWeb开发:Intellij IDEA+JFinal+Tomcat配置
- JFinal与websocket整合
- JFinal和Struts功能特点对比分析
- JavaWeb eclipse使用与断点调试总结
- javaWEB总结(5):GET与POST请求
- Jfinal数据库操作API总结
- JavaWeb总结
- javaweb总结
- javaweb总结
- JavaWeb总结
- Javaweb总结
- DataBinder.Eval与Bind对比总结
- 23种设计模式对比与总结
- Kotlin初体验
- Java常见面试题—Callable与Runnable接口
- Halcon 与 c# 混合编程读取并显示一张图片
- 九度[1007]-奥运排序问题
- Win10下在VirtualBox中安装WinXP
- JFinal与JavaWeb对比总结
- 图的邻接表实现(Java)
- catalog start with + switch database to copy的妙用
- linux操作系统共有几种版本
- Python中学习器流水线Pipeline
- 简易版侧滑Demo
- 用python对文本格式的数据进行统计处理
- 视频会议十大开源项目排行
- 获取xml节点的值