使用 JSP 技术和 JDBC 技术访问基于 Web 的动态数据

使用JSP+Servlet+JDBC+AJAX实现简单的用户动态登录 用户实体类(entity) package entity; /** *用户实体类 **@author linguoqiang *@version V1.0 * * @date 2018/11/3 20:42 * since 1.8 */ public class User { /** * 用户 */ private String userName; ... 阅读详情
<script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"> </script>

Noel J. Bergman (noel@jspdevguide.com)
CTO,Development Technologies,Inc./DevTech
2001 年 9 月

本文讨论使用 JSP 和 JDBC 技术把静态的、动态的及数据库内容集成在 Web 站点中。为了简洁明了的说明问题,文中的 JSP 页面使用短的 scriptlet 让 JSP 开发者接触到底层的 JDBC 概念,而不是把其隐藏在定制标记中。作者介绍一种集成 JavaBeans 组件和 JDBC 的主要设计方法,该方法同一直以来 JavaServer Pages 技术采用的、把 bean 用于 HTTP 的方式类似。他还提供实现该集成的代码。请在 讨论论坛同作者及其它读者分享对本文的理解。

JavaServer Page(JSP)技术建立在 Java Servlet 技术的基础之上,是核心的生成动态内容的服务器端 Java 体系结构。关系数据库是动态内容的来源之一。Web 站点使用关系数据库存储各类信息:目录项、图像、文本、关于注册成员的资料等等,从而管理从在线社区到电子商务交易的一切事务。本文讨论通过 Java 数据库连接(JDBC)把 JSP 技术应用于关系数据库。正是 JDBC 使 Java 程序可以使用关系数据库。

要深入理解本文,您应该熟悉 JDBC 和 SQL。

JDBC 基础知识
JDBC 是 Java 代码和 SQL 数据库之间的一座桥梁。主要的 JDBC 对象表示同数据库的连接及利用这些连接执行的语句。用于关系数据库的两种基本语句是查询和更新。两者都需要的一个前提条件就是,您首先要利用 java.sql.DriverManager 类同数据库建立连接。建立连接要花很长时间(就计算机时间而言),因此在 Web 服务器这种事务繁忙的环境中,您希望尽可能重用连接。这样的重用叫做建立连接池。

如果您的 JDBC 技术有些荒疏了,那么清单 1 中的代码片断说明的是同一个测试数据库建立 connection、创建用于该 connection 的 statement(语句)对象、发出 SQL 查询、处理 results(结果)及释放 JDBC 资源的全过程:

清单 1. 简单的 JDBC 代码


Connection connection = DriverManager.getConnection(URL, user, password);

Statement statement = connection.createStatement();

ResultSet results = statement.executeQuery(sqlQuery);



while (results.next())

{

    ... process query results ...

    logSQLWarnings(results.getWarnings());

}



results.close();

statement.close();

connection.close();

在现实生活中,JDBC 代码不会如此简单;因为需要处理异常和警告情况。清单 2 说明的是同一个 JDBC 示例,但添加了对 JDBC 异常和警告的处理。在这个示例中,异常和警告只记入日志,并且,对于异常情况,我们将异常终止操作。不过 finally{} 子句将确保资源清除过程进行。

对真实的结果处理过程在此仅作一下提示;我们将在本文后面的部分接着更仔细的分析这个问题。如果我们正在执行的不是数据库查询而是更新,那我们可以把 while 循环替换成如下语句:

int count = statement.executeUpdate(sqlUpdate);

除 executeQuery() 和 executeUpdate() 之外,Statement 类也支持一般的 execute() 方法。虽然这允许编写一般的 SQL 代码,但处理结果的过程更复杂了。

executeUpdate() 方法返回 update 语句所作用的行的总数。

如果这些代码清单中的材料显得陌生,您也许希望花些时间重温一下在参考资料部分中找到的一些 JDBC 教程信息。

JDBC 用于 JSP 页面
那么我们怎样结合使用 JDBC 和 JSP 技术才能使我们的动态内容来自数据库呢?

作为一条普遍的法则,良好的 JSP 惯例建议您应当把表示同模式行为分离。这与面向对象编程中的“模式-视图-控制器(MVC)”范例类似。分离原因之一是,基于 JSP 技术的应用很可能由程序员编写“模式(Model)”和“控制器(Controller)”组件,而由页面设计人员编写“视图(View)”组件。就 JSP 应用体系结构而言,负责表示的“视图”角色由 JSP 页面处理。负责对请求做出响应的“控制器”的角色通常由 servlet 担当,但许多 JSP 用户开始认识到用 JSP 页面来担任“控制器”的角色的优点。“模式”这一角色负责为应用实体的行为构建模式,典型情况下由 JavaBean 组件来担当。

除确定在 MVC 范例中的何处同数据库交互之外,关于在 JSP 页面中集成 JDBC 技术您有多种选择。例如,您可以使用 scriptlet 插入 JDBC 或使用标记库插入,还可以把它隐藏在定制标记或其它的类里。接下来我们要看看一些方式的示例并讨论其用法。

JSP scriptlet 示例
JSP 程序员新手有可能做的第一件事是写一个 scriptlet 来访问 JDBC。也许写出来的这个 scriptlet 象清单 3 中的示例一样使用 JDBC 来实现该页面的“点击计数器”。(这个页面的实际版本位于 JavaServer Page Developers Guide Web 站点上)

清单 3. JSP 页面通过 scriptlet 使用 JDBC


<jsp:directive.page import="java.sql.*" />

<jsp:scriptlet>

Class.forName("org.gjt.mm.mysql.Driver");

Connection connection = 

    DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "", "");

Statement statement = connection.createStatement();

int changed = 

    statement.executeUpdate("update counters set hitCount = hitCount   1 "  

                "where page like '"   request.getRequestURI()   "'");

if (changed == 0) statement.executeUpdate("insert counters(page) values('"  

                       request.getRequestURI()   "')");

ResultSet rs =

    statement.executeQuery("select hitCount from counters where page like '"  

                request.getRequestURI()   "'");

rs.next();

int hitCount = rs.getInt(1);

statement.close();

connection.close();

</jsp:scriptlet>



<HTML>

<HEAD>

<TITLE>JDBC scriptlet example</TITLE>

</HEAD>

<BODY>



<P>This page has been hit 

<jsp:expression>hitCount</jsp:expression>

times. The page counter is implemented by a JSP scriptlet calling

the JDBC package directly.</P>



</BODY>

</HTML>

该页面中有一个 scriptlet(高亮的第一部分)连接到数据库、创建 statement(语句)并试图对一个以页面的 URI 为主键的计数器记录进行更新。如果更新没有对任何行起作用,那么这个示例就假定没有这样的记录并添加一条。最后,这个 scriptlet 查询数据库中当前点击计数并把结果赋给一个局部变量。继续往下看,这个 JSP 页面的“表示”部分中高亮的 JSP 表达用于显示点击计数器的值。

注:您也许不希望真的以这种方式实现点击计数器。为每一次请求而更新数据库的开支是不必要的开销。但是,我们可以用点击计数器这个对数据库进行更新和查询的简单示例来说明在您的 JSP 页面中集成 JDBC 的各种途径。

尽管 JSP 页面能起作用,但它有许多问题。首先,不编程的页面设计者不会希望在页面中看到 scriptlet。坦白的讲,连程序员也不会希望在页面中有这类内容,因为它使页面的实际内容变得杂乱。第二,为简化示例,这个页面缺少异常处理,而这个异常处理应该是实际的 JDBC 代码中的一部分。第三,点击计数器的实现的确是嵌在 JSP 页面里的,因此对点击计数器的任何更改都需复制到使用点击计数器的每个 JSP 页面。

那么我们怎样修改这个 JSP 页面呢?一种常用的解决方案是使用标记库换掉 scriptlet。在下一个示例中,我们会看一下这种可选择的解决方案。

使用 DBTag 的标记库示例
通常善意的朋友和专家会告诉 JSP 程序员新手一些基本知识,其中之一就是不要使用 scriptlet。相反,他们会让 JSP 程序员新手使用定制标记。我们利用定制标记扩展 JSP 平台的功能:同代码库相连的定制 XML 样式标记实现预期功能。我们将会在下个示例中看到 DBTag 的工作情况。

Jakarta TagLibs Project 是 Jakarta Project(请参阅参考资料)的一个子工程,该工程是 Java Servlet 和 JavaServer Pages 技术的官方参考实现。

在 Jakarta TagLibs Project 的支持下开发的一个包是 DBTag 定制标记库(以前叫做 JDBC 标记库)。清单 4 里的 JSP 页面把 scriptlet 替换成定制标记,实现的点击计数器和清单 3 中的一模一样。

清单 4. JSP 页面使用 DBTag


<HTML>

<HEAD>

<TITLE>Jakarta DBTags example</TITLE>

</HEAD>

<BODY>



<%@ taglib uri="http://jakarta.apache.org/taglibs/dbtags" prefix="sql" %>



<%-- open a database connection --%>



<sql:connection id="conn1">

  <sql:url>jdbc:mysql://localhost/test</sql:url>

  <sql:driver>org.gjt.mm.mysql.Driver</sql:driver>

</sql:connection>



<%-- insert a row into the database --%>



<sql:statement id="stmt1" conn="conn1">

  <%-- set the SQL query --%> 

  <sql:query>

      insert counters(page,hitCount) values('<%=request.getRequestURI()%>', 0)

  </sql:query>

  <%-- the insert may fail, but the page will continue --%>

  <sql:execute ignoreErrors="true"/>

</sql:statement>



<%-- update the hit counter --%>



<sql:statement id="stmt1" conn="conn1">

  <%-- set the SQL query --%> 

  <sql:query>

      update counters set hitCount = hitCount   1 where page like '<%=request.getRequestURI()%>'

  </sql:query>

  <%-- execute the query --%>

  <sql:execute/>

</sql:statement>



<P>This page has been hit



<%-- query the hit counter --%>



<sql:statement id="stmt1" conn="conn1"> 

  <sql:query>

    select hitCount from counters where page like '<%=request.getRequestURI()%>'

  </sql:query>

  <%-- process only the first row of the query --%>

  <sql:resultSet id="rset2" loop="false">

      <sql:getColumn position="1"/>

  </sql:resultSet>

</sql:statement>



times. The page counter is implemented using the Jakarta Project's

DBTags tag library, calling JDBC indirectly.</P>



<%-- close a database connection --%>

<sql:closeConnection conn="conn1"/>



</BODY>

</HTML>

我不知道您的感受如何,可我感觉到有一点失望。在我看来这似乎还不如 scriptlet 示例清晰,而且我知道也不会有哪个不编程的 HTML 页面设计者会对此感到满意。但是问题出在哪儿呢?毕竟,我们已听从了大多数人的建议:我们抛弃了 scriptlet,用定制标记取而代之。

开发定制标记库相对简单些,但也要费些思考,而且费时。我常推荐的做法是标记库的作者们先用 scriptlet 为标记行为建立原型,再把这些 scriptlet 变成标记。

一种可选择的解决方案是使用 Allaire 的 JRun Server Tag(JST),使您可以通过把每个标记作为一个 JSP 页面(以 .jst 为扩展名)来编写,从而为标记库建立原型。JST 把页面转变成运行时标记处理程序,这样 JST 技术对客户机页面来说就是透明的。虽然 Allaire 宣称“目标是把 JST 建成一种可移植技术以使 J2EE 社区的所有成员都能从中受益”,但 JST 目前还只能在 JRun 中使用。时间将会证明 JST 是否会成为开发标记更通用的工具。与此同时,我们发现 scriptlet 为开发标记的业务逻辑奠定了良好的基础;逻辑经调试后,我们把它迁移成为标记处理程序类。

关于标记库 Allaire 没有告诉您的是:标记设计是一种语言设计。迄今为止,所写的大多数标记库是由程序员为程序员写的;这些标记的语义适合于其它的程序员。不仅如此,还记得模式和表示的分离吗?DBTag 对这一点不太支持。sql:getColumn 标记同 jsp:getProperty 动作类似:它把标记的结果直接发给输出流。这给 DBTag 的利用与把输出转化成要求的格式之间的分离带来了困难。最后,请注意清单 3 和 清单 4 的逻辑差异。DBTag 的 execute 标记使用所有来自通过 JDBC 发送的 update 语句的更新计数;可以回收的只有查询结果。这意味我们无从知道 update 语句更新了多少行。因此我们不得不切换 update 和 insert 语句;我们总是试图插入新记录、迫使 DBTag 怱略任何错误,然后执行更新。

对 DBTag 标记库公正的评价是,对于程序员来说这是个不错的标记库。除更新计数的使用外,代码提供的与 JDBC 的映射相当不错。但其中也存在问题:标记提供的只不过是对 JDBC 包的直接翻译。除隐藏了一些异常处理之外,标记库实际上并没有提供对 scriptlet 任何抽象。这对从功能中分离表示当然于事无补。

因此,真正的问题不在于是使用 scriptlet 还是使用标记;这种问题不是分离功能和表示的问题的原因,而是结果。解决方案是要以适当的说明级别上为表示页面的作者提供更高级别的功能。认为标记优于 scriptlet 的原因在于:根据定义,scriptlet 是编程,而标记可以表示高级概念。

对表示页面隐藏 JDBC
将 JDBC 同 JSP 技术集成时,我们希望对表示作者尽可能多的隐藏该集成。在我们显现数据库概念的地方,我们希望在恰当的抽象级别上显现这些概念。这一方法引出了我们的下一个示例。

在清单 5 中的示例中,我们对表示页面隐藏了 JDBC 集成。(这个页面的实际版本位于 JavaServer Pages Developers Guide Web 站点)

清单 5. 隐藏了 JDBC 的 JSP 页面


<jsp:directive.include file="/pagelets/hitCounter.jsp" />



<HTML>

<HEAD>

<TITLE>JDBC hidden example</TITLE>

</HEAD>

<BODY>



<P>This page has been hit 

<jsp:getProperty name="hitCounter" property="int" />

times. The page counter is implemented indirectly: a JavaBeans component containing the

hit count is inserted into the environment and referenced within the page using

the JSP getProperty action. The JSP page doesn't have any exposure to JDBC.</P>



</BODY>

</HTML>

被包含的 hitCounter.jsp 文件负责设置环境。内容可以是 scriptlet、标记或只是一个 taglib 伪指令;只要是为表示页面建立预期环境的都可以作为内容。如果您愿意,您可以把 getProperty 操作替换成定制标记;例如:



This page has been hit 

<page:hitcounter />

 times.

如前所述,这些点击计数器示例纯粹用作说明;每个页面都执行这样的数据库操作将会是不必要的开销。上面这个示例说明事实上您希望以何种方式显现点击计数器。通过把它隐藏在定制标记里,我们就把该实现彻底隐藏了起来。现在我们可以聚集点击计数运行时信息,并周期性的更新数据库(比如,在每次会话结束时)。甚至连存储方式(数据库或是别的)也对表示页面作者隐藏了。这正是我们在 DevTech 实现点击计数器的方式:我们利用 bean 类实现点击计数器模式行为。标记把该行为结合到了我们的页面里。

集成 JavaBean 组件
到目前为止,示例一直都相当简单,但大多数数据库操作都比这些简单的查询和更新要复杂。因此,既然我们已经讨论了把 JDBC 用于 JSP 页面的一些基本原则,就让我们用一个略微复杂些但肯定更加通用的一类应用来结束这篇文章。

这一部分的示例(下面清单 9)将指出一种方法以支持 Web 站点上访问者提供的内容。换句话说,我们希望允许访问者读取与某一 URI 关联的数据库内容并撰写额外的内容。这样的内容在现在的 Web 站点上相当常见。同样的基本部分可用于构造:

  • 评论页面,例如在 Amazon.com 找到的那些页面
  • 链接页面
  • 公告牌
  • Wikiweb

通过由不同技术背景的设计人员编写,本例中 JSP 组件稍微再精细些的版本就可以实现看上去截然不同的 Web 页面。这些页面看上去的唯一的相同之处就是用于访问者撰写内容。

我们的 annotation(注释)示例使用 HTML 表单。HTML 表单用于 JSP 时,使用属性映射到表单域的 bean 变得方便了。这使 setProperty 标记可以变戏法:

清单 6. 映射到表单的 Bean 实例


<%-- setup a bean instance that matches our form --%>

<jsp:useBean id="instance-name" class="bean-class" ... />

<%-- set all bean properties that match a form field --%>

<jsp:setProperty name="instance-name" property="*" />

映射 bean 和 ResultSet
示例使用 com.devtech.sql 以使说明简洁。示例使用 Java Reflection 和 Introspection,依靠列名及属性名提供 JDBC 数据和 bean 属性间的映射。您可以把 DevTech 包替换成自己的代码。

集成 JavaBean 组件是 JSP 技术设计方面的一个过人之处。不幸的是,bean 和 JDBC 之间的集成根本不是无缝的,因此我们针对 DevTech 的 JDBC 工作开发了一个包,它不仅提供了 bean 和 JDBC 的集成,而且还有必要的异常处理,从而使程序员不必应付这些细节。

annotation(注释)示例使用 com.devtech.sql 包中的两种查询和更新方法。这里用到的查询方法传递一个 bean 类、一个 SQL 查询和一个 Object 数组填充查询中的占位符。在这种情况下,仅有的占位符是给页面的 URL 的。结果是一个数据库游标对象,它必须是一种迭代器。

清单 7. 数据库游标对象


dataBase.queryCursor(AnnotationDBBean.class, new String[] { URL },

	"select page, author, annotation, DATE_FORMAT(whenPosted, '%W %d%b%y %T')"  

	" as whenPosted from annotations where page like ?");

这个查询方法的有趣之处在于指定类型的 bean 将会为您实例化,只要 bean 属性名同 ResultSet 中的列名相对应,属性值就会被自动设置。每次您用游标选择下一行时,bean 的属性就会根据 ResultSet 被自动设置。

用到的这种特殊更新方法有一个 bean 实例、一个 String 数组及一条 update 语句作为参数。String 数组值规定了用来填充更新中的占位符的预期 bean 属性。在这种情况下,page、author 和 annotation 属性是根据 bean 选择的。

清单 8. 更新方法


int count = dataBase.update(annotationBean,

	new String[] { "page", "author", "annotation" },

	"insert into annotations(page, author, annotation) values(?, ?, ?)");

我们的 JSP 页面示例 annotations.jsp 如清单 9 中所示。高亮的部分指出两个可以用定制标记替换的 scriptlet,如清单 10 中所示。一些为页面设计者提供帮助的 JSP 组件、把动态内容放到页面上去的 getProperty 操作以及标准 HTML 组成了页面的剩余部分。使用 JSP 注释的原因是因为 JSP 注释是私有的,不会出现在输出流中。

清单 9. annotation(注释)的 JSP 页面


<jsp:directive.include file="/pagelets/annotate.jsp" />

<%-- 

By the time we arrive here, the annotation bean has been established, and if the

form is submitted, the contents will be posted to the database. The page

property is initialized. If the author is known during this session, that property

is also initialized.



Bean:		"annotation"

Properties:	String page;

		String author;

		String annotation;

		String whenPosted;



Access to any bean property follows the format:



	<jsp:getProperty name="annotation" property="property-name" />   



--%>



<HTML>

<HEAD>

<TITLE>Comments for <jsp:getProperty name="annotation" property="page" /></TITLE>

</HEAD>



<BODY>

<p align="left"><font size=" 1">

Comments for <i><jsp:getProperty name="annotation" property="page" /></i>

</font>.</p>

<CENTER><HR WIDTH="100%"></CENTER>



<!-- Annotation Submission Form -->

<FORM method="POST">

<TABLE>

<TR>

	<TH align="left">Name:</TH>

	<TD><INPUT type=text name=author size=50 maxlength=60

        value="<jsp:getProperty name="annotation" property="author" />"> </TD>

</TR>

<TR>

	<TH valign="top" align="left">Note:</TH>

	<TD><TEXTAREA name=annotation cols=40 rows=5 wrap=virtual>

        <jsp:getProperty name="annotation" property="annotation" /></TEXTAREA></TD>

</TR>

<TR>

	<TD align="center" colspan="2"><INPUT type=submit value="Add Comment"></TD>

</TR>

</TABLE>

</FORM>

<!-- End of Annotation Submission Form -->



<!-- beginning of annotations -->

<%--

The following section iterates through all annotations in the database for the

requested page. To change the look of the page, just change anything in the

demarcated area.

--%>



<jsp:scriptlet>

Database.Cursor annotations = annotation.getCursor();

while (annotations.next(annotation) != null)

{

</jsp:scriptlet>

<%-- beginning of annotation change area --%>



<CENTER><HR WIDTH="100%"></CENTER>

From: <jsp:getProperty name="annotation" property="author" /></A> 

at <jsp:getProperty name="annotation" property="whenPosted" /><BR>

<jsp:getProperty name="annotation" property="annotation" /><BR>



<%-- end of annotation change area --%>

<jsp:scriptlet>	

}

annotations.close();

</jsp:scriptlet>

	

<!-- end of annotations -->

</BODY>

</HTML>

定制标记等价程序清楚,但不提供信息:

清单 10. 定制标记等价程序


<sql:results queryName="annotations" bean="annotation">

<CENTER><HR WIDTH="100%"></CENTER>

From: <jsp:getProperty name="annotation" property="author" /></A> 

at <jsp:getProperty name="annotation" property="whenPosted" /><BR>

<jsp:getProperty name="annotation" property="annotation" /><BR>

</sql:results>

我们在这个示例中使用 scriptlet 只是要让您(一位程序员)知道正在发生的事情。如果用陈述性的标记替换 scriptlet,那么页面设计者会很清楚,但您却一头雾水。

逻辑并不复杂。annotation.getCursor() 调用能得到同服务器的连接、发出查询并在结果集建立一个数据库游标对象 annotations。每次调用 annotations.next() 时,从结果集中取出一个新行,其中的值移到 bean 里,方法返回的正是这个 bean 的引用。所用的这个特殊的 next() 方法使用一个要植入的 bean 参数。虽然我们本可以使游标为每一行实例化一个新的 bean,但反复使用一个 bean 更加高效。

请注意真正的查询及更新都没有在表示页面中出现。被包括的页面设置表示页面环境,也包括 setProperty 和 update 操作。这些操作独立于表示页面;只有注释 bean 的属性所包含的 contract 是重要的。这遵守了将表示与模式行为相分离的策略。页面设计者完全有能力更改表示是如何呈现的,但无从得知数据库是如何集成的。如果更改在数据库更新或查询时生效,就应当由 JSP 程序员负责。

总结
本文对结合使用 JavaServer Page、JavaBean 和 JDBC 技术并通过关系数据库生成动态内容的进行了总结性介绍。我们从对于 JSP 程序员新手来说最显而易见的方法(scriptlet)开始。我们看到不加控制的使用 scriptlet 是如何使逻辑和表示纠缠在一起的,使两者都难以维护。我们还看到标记库并不一定会改善 MVC 分离,如果用编程术语来表示标记,则页面设计人员可能无法理解使用这样的标记的页面。最后,我们看了更为复杂的示例,这些示例说明了几种使数据库访问与内容表示分离的途径。

现在您应该对在对页面设计人员隐藏真实的数据库访问的同时如何把数据库内容集成到一个 Web 站点中有一些基本概念。还请注意,对您(一个程序员)而言,几乎不含信息的那些示例是最适合于页面设计人员的示例。当您为 JSP 解决方案制定计划时,千万要为页面设计人员设身处地地想一想。

关于作者
Noel Bergman 在面向对象编程方面的经历持续 20 多年,包括参与最早的 CORBA 和“公共对象服务任务小组(Common Object Services Task Forces)”。Colorado Software Summit 及其它的业界会议上他一直作为受欢迎的演讲者享有盛誉;他还担任导师和顾问,为客户提供量身定制的服务。

目前,Noel 正涉足于使用开放源代码免费软件为手持设备编程以及开发交互式以数据库为后台的 Web 站点。最后,Noel 还是 GNUJSP 的合著者,GNUJSP 是 JavaServer Pages 技术的开放源代码实现,而且他还首创了 JSP Developers Guide Web 站点。
通过JSP展示MySQL数据库内容的Web应用 JSP页面以.jsp为后缀,其核心在于能够将Java代码与静态模板混合在一起。当JSP页面被首次访问时,服务器会将JSP转换为Servlet,然后由Servlet引擎执行转换后的Java代码,并生成HTML发送给客户端。这种方式简化了Java Web开发过程。JavaServer Pages Standard Tag Library(JSTL)提供了一系列标准化的标签,允许开发者在JSP页面中执行常见的任务,如数据格式化、条件判断、迭代以及引入资源等。 阅读详情

相关推荐

JSP+JDBC+MySQL实现留言板及用户管理功能

JSP(Java Server Pages)是一种基于Java技术,用于开发动态网页的技术。它允许开发者将Java代码嵌入到HTML页面中,这样可以将页面的展示逻辑和业务逻辑分离,从而提高开发效率和维护便捷性。JSP主要处理用户请求并生成动态Web内容。JDBC(Java Database Connectivity)是一个Java API,可以使得Java应用程序执行SQL语句。它定义了Java应用程序与数据库之间进行交互的一套标准API。

weixin_42452924的博客 849

jsp动态网页开发基础

BS与CS的区别 C/S(client- server): 客户机——网络——服务器 如QQ 保密性高和硬件交互性高 B/S(browser- server):浏览器——网络——服务器 如浏览器 和硬件交互费点劲 JDBC链接数据库的基本步骤 1.加载JDBC驱动 2.建议数据库连接 3.执行SQL语句 4.处理返回结果 5.数据库访问结束后,进行资源释放 URL称统一资源定位符 组成部分:http://localhost:8080/ 协议,主机名,路径 Web容器处理Jsp文件请求经过三个阶段 翻译阶段:

m0_50854913的博客 255

基于JSP+JDBC的完整登录系统实战(含数据库交互)

JavaServer Pages(JSP)是一种基于Java的服务器端动态网页开发技术,允许开发者将HTML静态内容与Java代码动态嵌入同一页面。其本质是Servlet的扩展,由容器(如Tomcat)在首次请求时自动编译为Servlet类并生成响应。JSP通过<% %><%= %>等脚本元素实现逻辑控制与数据输出,结合JSTL和EL表达式可提升可读性与开发效率。在接口中定义静态路径常量:在任意类中引用:一旦路径变更,仅需修改一处即可全局生效。

weixin_42511373的博客 1032

使用JDBC动态加载JSP

先来讲一下web.xml,主要是想讲解通过servlet来访问页面(为了jsp页面的安全性,将jsp文件存到web-inf中,客户端通过访问Servlet类来实现界面的获取) 创建一个servlet类 import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.Ht

moluchase的专栏 724

构建基于JSP和JavaBean的网上花店系统

DDL用于定义或修改数据库结构,如创建、修改和删除数据库对象。以下是一些基本的DDL操作:CREATE:创建新的表、索引、视图或存储过程等。ALTER:修改现有数据库对象的结构。DROP:删除表、索引、视图或存储过程等。JDBC(Java Database Connectivity)是一种Java API,提供了连接和执行SQL语句的能力。JDBC 是 Java SE 的一部分,它提供了一种标准的方法,使得 Java 程序能够访问数据库管理系统(DBMS)中的数据。

weixin_42576410的博客 930

天津理工大学Web应用程序设计与开发大作业:综合应用【JSP+EasyUI+Servlet+JDBC】的报告

天津理工大学Web应用程序设计与开发大作业:综合应用【JSP+EasyUI+Servlet+JDBC】的报告 【大作业】实现根据学院名称、专业名称两个条件查询学生信息,数据库及表结构自己定义和设计,学院名称和专业名称由数据库表维护(可直接通过数据库管理软件维护)。 只有报告,没提供代码,可以直接提交 一共有四份,全部不一样,这是第一份

JSP和JDBC的使用

查询数据 <%@ page import="java.sql.*" %> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> <!DOCTYPE html> <html lang="en">

fjd7474的博客 911

从0开始学GEE python——Google Earth Engine (GEE) 和 geemap 库来获取 Sentinel-2 卫星影像,并将其可视化

这段代码的目的是从 Sentinel-2 卫星影像中获取特定地点的影像,并将其可视化在地图上。通过设置合适的波段和可视化参数,用户可以清晰地查看该地区的卫星影像。

此星光明博客 1167

一个web端的基于servlet和jdbc的学生表操作示例

目录   目标 步骤: MVC之间的关系: 具体实现  一:建立数据库 二:利用jdbc连接数据库。  三:绘制jsp显示页面  四:实现Java程序与页面之间的链接--------servlet 目标 实质:实现web界面化对数据库的查询显示,增加,删除,更改。 应用:对软件用户的新建,更改,删除等。 示例:有一张通信工程的学生表,其中包含学生的学号,姓名,班级,性别,...

zuo_h_dr的博客 917

FPGA实战:AXI BRAM Controller配置避坑指南(Vivado 2023版)

本文详细解析了Vivado 2023环境下AXI BRAM Controller的配置技巧与避坑指南,涵盖AXI4协议转换、BRAM地址空间配置、信号异常处理及突发传输优化等核心内容。针对写时序冲突、跨时钟域处理等常见问题提供实用解决方案,帮助开发者提升FPGA系统性能与稳定性。

q1w3e5r7t9y的博客 340

Colmap中 patchmatch源码

惊世骇俗的Colmap PatchMatch源码 500多行,简明易懂 先了解PatchMatch的options: max_image_size: 任一维度的最大图像尺寸 gpu_index: gpu的下标 depth_min,depth_max: 随机采样的深度范围 window_radius:用于计算NCC(两图片的归一化互相关),NCC的计算需要用到 win_size. 图像匹配 | NCC 归一化互相关损失 | 代码 + 讲解 - 知乎 (zhihu.com) window_step: 用.

qq_24884193的博客 2209

Java Jsp

可以实现交互功能(客户端和服务器端产生请求和响应)可以实现html静态页面无法实现的动态更新数据功能。(java服务器端页面技术)

zhurui19940321的博客 75

详解各类以太网标准10BASE-T/100BASE-T4/100BASE-FX/1000BASE-X等

以太网是现实世界中最普遍的一种计算机网络。以太网有两类:第一类是经典以太网,第二类是交换式以太网,使用了一种称为交换机的设备连接不同的计算机。经典以太网是以太网的原始形式,运行速度从3-10 Mbps不等;而交换式以太网正是广泛应用的以太网,可运行在100Mbps、1000Mbps和10000Mbps高速率,分别以快速以太网、千兆以太网和万兆以太网的形式呈现

不积跬步,无以至千里! 5万+

JSP原理、使用

1、JSP 1.1、什么是JSP Java Server Pages : Java服务器端页面,也和Servlet一样,用于动态Web技术! 最大的特点: 写JSP就像在写HTML 区别: HTML只给用户提供静态的数据 JSP页面中可以嵌入JAVA代码,为用户提供动态数据 1.2、JSP原理 思路:JSP到底怎么执行的! 代码层面没有任何问题 服务器内部工作 tomcat中有一个work目录; IDEA中使用Tomcat的会在IDEA的tomcat中生产一个.

lpw666_的博客 811

频偏估计技术:从原理到5G应用的实战解析

本文深入解析了5G通信中的频偏问题及其核心技术。频偏如同调不准的旋钮,会导致信号失真与载波间干扰。文章详细拆解了整数倍与小数倍频偏估计两大核心方法,重点剖析了基于循环前缀和基于同步信号块的算法原理与优劣,并结合eMBB、mMTC、URLLC三大5G应用场景,提供了实战算法选择策略与参数调优避坑指南。

weixin_29218963的博客 262

Zemax操作33--5倍激光扩束器

5倍扩束

lzy750750的博客 2931

JSP与Servlet整合数据库开发:构建Java Web应用的全栈指南

本文介绍了基于JSP+Servlet+JDBC的Java Web全栈开发技术,重点讲解了如何构建用户管理系统。内容涵盖:1)技术栈架构,解析了JSP、Servlet和数据库在MVC模式中的角色与交互流程;2)开发环境准备,包括JDK、Tomcat和MySQL的安装配置;3)标准的项目结构设计,遵循分层思想;4)数据库设计规范,以users表为例说明设计原则。文章通过架构图和SQL示例,系统性地展示了从环境搭建到数据库设计的完整开发流程,为Java Web应用开发提供了实用指南。

2301_79536841的博客 2407

KiCad自动布线实战:FreeRouting插件安装与使用指南

在PCB设计流程中,布线环节往往占据大量重复性工作,尤其对于中小型双面板,成百上千条飞线的手动连接既繁琐又易出错。自动布线技术通过算法在给定设计规则和元件布局的基础上自动规划走线路径,能显著提升布线效率。FreeRouting作为一款开源自动布线器,与KiCad通过DSN/SES标准中间格式无缝配合,让工程师将精力集中于关键信号和布局优化,而将常规网络交给工具处理。本文从自动布线的原理与边界出发,讲解了FreeRouting的安装、DSN导出、参数设置、自动布线及结果回传的完整流程,并结合实际案例展示了在S

weixin_32025789的博客 277

零基础学JavaWeb开发(十一)之 jsp+servlet+jdbc开发航班系统

MVC架构模式MVC是一个架构模式,它强制性的使应用程序的输入、处理和输出分开。使用MVC应用程序被分成三个核心部件:模型、视图、控制器。他们各自处理自己的任务。 1.视图视图是用户看到并与之交互的界面 jsp2.模型模型表示企业数据(数据模型:dao)和业务规划及操作(业务模型:service)3.控制器控制器表示用户的输入并调用模型和视图去完成用户的需求。常见的MVC组件:Struts,Spring MVC,JSF

weixin_54828627的博客 1461

AI原生应用中的数据治理:从采集到应用的完整方案

当AI从"辅助工具"进化为"应用核心"(如ChatGPT、智能驾驶系统),传统数据管理方式已无法满足需求:模型需要更精准的训练数据、业务需要更实时的决策支持、法规需要更严格的隐私保护。本文聚焦AI原生应用的数据全生命周期治理(从采集→清洗→标注→存储→应用→归档的完整链路),覆盖技术方案、工具选择和实践要点。本文将按"场景引入→核心概念→技术方案→实战案例→未来趋势"的逻辑展开,重点通过"奶茶店原料管理"类比,解释数据治理的关键环节;结合Python代码演示核心技术(如异常值检测、主动学习标注);

SuperAGI2025 882

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

JSP 连接数据库

JSP 连接数据库方法与实践 JSP 连接数据库主要采用 JDBC 技术,通过加载驱动、建立连接、执行 SQL 并处理结果实现数据交互。对于 MySQL 8.0+,需使用 com.mysql.cj.jdbc.Driver 驱动,并在连接字符串中添加时区参数防止报错(serverTimezone=UTC)和编码参数避免中文乱码(useUnicode=true&characterEncoding=utf-8)。连接步骤包括:加载驱动、创建连接、执行 SQL、处理结果集和关闭连接。此外,JSTL SQL

likuoelie的博客 1002

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

JavaWeb一JSP简介

本篇想谈谈为啥会出现JSP技术和简单的框架。JavaWeb中有两个地方挺难的,一个是JDBC相关的内容,另一个就是JSP与Servlet(JSP本质也是Servlet)。JDBC之所以让我感觉很难,在于JDBC是我接触的第一个“非Java类”形式的知识点。它是一个接口,而不是以前学的Java类。这让我有好一阵子缓不过来。啥叫接口?JDBC做成接口的好处有什么?以及JavaWeb中几次jdbcUti...

肥叔菌的博客 1万+

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

java jsp技术_一个开发人员眼中的JSP技术(上)

一个开发人员眼中的JSP技术(上)更新时间:2006年10月13日 00:00:00 作者:(作者:天译编译 2000年12月01日 14:26)JavaServerTM Pages(JSP)技术为我们提供了一种建立动态网页的简单方法,而且也简化了构造web程序的工作。本文从一个开发人员的角度对JSP技术做了一个全面介绍(并提供了一些JSP实例程序)。前言JavaServer Pages技术可...

weixin_34837898的博客 376

html 引入 jsp c标签,jsp页面和C标签.

1.背景介绍JSP全称Java Server Pages,是一种动态网页开发技术。它使用JSP标签在HTML网页中插入Java代码。标签通常以结束。JSP是一种Java servlet,主要用于实现Java web应用程序的用户界面部分。网页开发者们通过结合HTML代码、XHTML代码、XML元素以及嵌入JSP操作和命令来编写JSP。JSP通过网页表单获取用户输入数据、访问数据库及其他数据源,然后...

weixin_30126739的博客 1575
上一篇: 再谈客户端的 Java 技术
下一篇: J2EE的客户端
java169
博客等级 码龄18年 27粉丝 2568原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值