`
huibin
  • 浏览: 754001 次
  • 性别: Icon_minigender_1
  • 来自: 郑州
社区版块
存档分类
最新评论

JForum论坛单点登录的几种实现方式 (CAS和Cookie) 收

阅读更多

一、用CAS实现Jforum的单点登录

 

(一)CAS客户端应用的web.xml配置

CAS和jforum的安装过程本文就不介绍了,下面是jforum配置CAS服务器连接需要在web.xml中添加的配置:

   <filter>

        <filter-name>CASFilter</filter-name>

        <filter-class>edu.yale.its.tp.cas.client.filter.CASFilter</filter-class>

        <init-param>

            <param-name>edu.yale.its.tp.cas.client.filter.loginUrl</param-name>

            <param-value>https://localhost:8443/cas/login</param-value>

        </init-param>

        <init-param>

            <param-name>edu.yale.its.tp.cas.client.filter.validateUrl</param-name>

            <param-value>https://localhost:8443/cas/proxyValidate</param-value>

        </init-param>

        <init-param>

          <param-name>edu.yale.its.tp.cas.client.filter.serverName</param-name>

          <param-value>localhost:8000</param-value>

        </init-param>

    </filter>

    <filter-mapping>

        <filter-name>CASFilter</filter-name>

        <url-pattern>/*</url-pattern>

    </filter-mapping>

 

一开始我调试jforum的单点登录的时候,首先在地址栏输入http://localhost:8000/cas/login?service=http://localhost:8000/jforum/user.jsp

(其中user.jsp是我自己添加JSP页面做测试用 ),在CAS页面输入用户名和口令确认后,页面自动跳转到http://localhost:8000/jforum/user.jsp?ticket= ticket=ST-5-Ih4fJNYyWlhFfywfeOwuVAFZn1vKOOVAgpD-20

Ticket是生成的票据,然后用这个ticket做参数访问:

https://localhost:8443/cas/serviceValidate?service= http://localhost:8000/jforum/user.jsp&ticket= ST-5-Ih4fJNYyWlhFfywfeOwuVAFZn1vKOOVAgpD-20

如果成功,返回的页面中出现登录成功的用户名,打开html源文件,内容为:

<cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>

       <cas:authenticationSuccess>

              <cas:user>admin</cas:user>

       </cas:authenticationSuccess>

</cas:serviceResponse>

如果失败,页面显示ticket 'ST-2-4ffpnvHKv1NH5So7uWvFdVNrbHsaPAfROXx-20' not recognized,html源文件内容:

<cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>

       <cas:authenticationFailure code='INVALID_TICKET'>

              ticket 'ST-2-4ffpnvHKv1NH5So7uWvFdVNrbHsaPAfROXx-20' not recognized

       </cas:authenticationFailure>

</cas:serviceResponse>

(二)Jforum配置单点登录

Jforum的WEB-INF\config目录下有一个SystemGlobals.properties文件,配置SSO需要更改此文件的几个配置参数:

authentication.type = sso

#CasUserSSO类用于CAS单点登录,下面将讲述此类的代码

sso.implementation = com.iss.common.sso.CasUserSSO

#CasCookieSSO是基于Cookie的一个简单的单点登录,代码见下文

#sso.implementation = com.iss.common.sso.CasCookieSSO

#下面的redirect我也不太清楚具体有什么用

sso.redirect = https://localhost:8443/cas/

(三)当把jforum的web.xml的CAS filter注释掉以后,使用下面的JSP通过CAS单点登录票据验证的一个示例,其中URL应带service参数,如:

http://localhost:8000/cas/login?service=http://localhost:8000/jforum/testsso.jsp

登录CAS成功后,返回的页面url带有一个ticket参数,见下面的返回URL:

http://localhost:8000/jforum/testsso.jsp?ticket=ST-5-VbM7tdMPeLD1WlH2ZGnocVGTbAY73ff4y17-20

Tomcat控制台显示下面的输出说明票据认证通过:

<cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>

        <cas:authenticationSuccess>

                <cas:user>admin</cas:user>

        </cas:authenticationSuccess>

</cas:serviceResponse>

下面是testsso.jsp:

 

<%@ page contentType="text/html;charset=GBK"%>

 

<%@ page import="java.util.*"%> 

<%@ page import="net.jforum.context.RequestContext"%> 

<%@ page import="net.jforum.entities.UserSession"%> 

<%@ page import="net.jforum.util.preferences.ConfigKeys"%> 

<%@ page import="net.jforum.util.preferences.SystemGlobals"%> 

<%@ page import="org.apache.log4j.Logger"%> 

<%@ page import="net.jforum.sso.*"%> 

 

<%@ page import="java.io.*"%> 

<%@ page import="edu.yale.its.tp.cas.client.*"%> 

<%

    String username = null;

      String errorCode = null;

      String errorMessage = null;

      String xmlResponse = null;

      String ticket = request.getParameter("ticket");

    System.out.println("获取的ticket为:"+ticket);

       ServiceTicketValidator sv = new ServiceTicketValidator();

        if(ticket != null)

        {

            try

            {

         

                sv.setCasValidateUrl("https://localhost:8443/cas/serviceValidate");

             sv.setServiceTicket(ticket);

                sv.setService("http://localhost:8000/jforum/testsso.jsp");

             sv.validate();  

             xmlResponse = sv.getResponse();

               

              if (sv.isAuthenticationSuccesful())

                {

                 username = sv.getUser();

                     System.out.println("认证成功,获得的用户名为:");

                     System.out.println(username);

             }

                else

                {

                  errorCode = sv.getErrorCode();

                    errorMessage = sv.getErrorMessage();

                     System.out.println("认证失败!!!!!!!!!!!");

             }

            }

            catch (Exception exc)

            {

               System.out.println(exc.getMessage());

          }

      }

%>

 

edu.yale.its.tp.cas.client.ServiceTicketValidator是casclient.jar中的类。

 

(四)当Jforum的web.xml中不配置CAS Filter时,如何实现单点登录类?

这种情况类似于(三),但问题是如何在Java类中实现单点登录,而不是在jsp中实现。

我从网上找到一个名为CasUserSSO.java的程序,并按步骤(二)的说明将此类作为单点登录类配置,但编译运行后,在浏览器地址栏输入http://localhost:8000/cas/login?service=http://localhost:8000/jforum/user.jsp

(user.jsp是我自己写的一个显示简单输出的jsp文件, http://localhost:8000/jforum/user.jsp是我在CasUserSSO.java里面作为service参数的),CAS登录成功后Tomcat控制台没有显示单点登录的认证信息,好象CasUserSSO没有调用到,于是我修改了CasUserSSO.java,将

sv.setService("http://localhost:8000/jforum/user.jsp")改为sv.setService(java.net.URLEncoder.encode(http://localhost:8000/jforum/forums/jforum.page?module=forums&action=list"));

重新编译运行后,地址栏中输入http://localhost:8000/cas/login?service= http%3A%2F%2Flocalhost%3A8000%2Fjforum%2Fforums%2Fjforum.page%3Fmodule%3Dforums%26action%3Dlist

注意service等号右面的必须是java.net.URLEncoder.encode转换后的字符串(http://localhost:8000/jforum/forums/jforum.page?module=forums&action=list转换后的字符串为http%3A%2F%2Flocalhost%3A8000%2Fjforum%2Fforums%2Fjforum.page%3Fmodule%3Dforums%26action%3Dlist)

 

注意地址栏中service后不要带空格,在地址栏输入http://localhost:8000/cas/login?service=http%3A%2F%2Flocalhost%3A8000%2Fjforum%2Fforums%2Fjforum.page%3Fmodule%3Dforums%26action%3Dlist,CAS登录后(我的jforum配的超级管理员帐号是admin/123),出现jforum页面,这说明CAS单点登录成功!!!

Tomcat控制台显示:

 

<cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>

        <cas:authenticationSuccess>

                <cas:user>admin</cas:user>

        </cas:authenticationSuccess>

</cas:serviceResponse>

 

请大家一定要注意,在地址栏中service=后面的URL必须是encode转换后的,因为开始没转换,我还以为是CasUserSSO写的有问题,网上下载的CasUserSSO中的

sv.setCasValidateUrl("https://localhost:8443/cas/login");我认为是有问题的,会出现一个很奇怪的异常,显示信息为org.xml.sax.SAXParseException: The reference to entity "ticket" must end with the ';' delimiter.我改为:

sv.setCasValidateUrl("https://localhost:8443/cas/serviceValidate")则不会出现这个问题。见下面的CasUserSSO.java:

 

package com.iss.common.sso;

 

import net.jforum.context.RequestContext;

import net.jforum.entities.UserSession;

import net.jforum.util.preferences.ConfigKeys;

import net.jforum.util.preferences.SystemGlobals;

import org.apache.log4j.Logger;

import net.jforum.sso.*;

import java.util.*;

import java.net.*;

 

import edu.yale.its.tp.cas.client.*;

 

public class CasUserSSO implements SSO

{

    static final Logger logger = Logger.getLogger(CasUserSSO.class.getName());

    public String authenticateUser(RequestContext request)

    {

        String username = null;

      String errorCode = null;

      String errorMessage = null;

      String xmlResponse = null;

     // 开始setServiceTicket单点登录代码

 

      String ticket = request.getParameter("ticket");

        logger.info("获取的ticket为:"+ticket);

 

       ServiceTicketValidator sv = new ServiceTicketValidator();

       

      if(ticket != null)

        {

                       try

            {

                logger.info("ticket为非空!!!!!!!!!!!!!!!!!");

                sv.setCasValidateUrl("https://localhost:8443/cas/serviceValidate");

                //sv.setCasValidateUrl("https://localhost:8443/cas/login");

                System.out.println(java.net.URLEncoder.encode("http://localhost:8000/jforum/forums/jforum.page?module=forums&action=list"));

                sv.setService(java.net.URLEncoder.encode("http://localhost:8000/jforum/forums/jforum.page?module=forums&action=list"));

                sv.setServiceTicket(ticket);

             logger.info("开始验证............");

             sv.validate();  

             xmlResponse = sv.getResponse();

                //System.out.println(xmlResponse);

              if (sv.isAuthenticationSuccesful())

                {

                 username = sv.getUser();

                    logger.info("认证成功,获得的用户名为:");

                    logger.info(username);

             }

                else

                {

                  errorCode = sv.getErrorCode();

                    errorMessage = sv.getErrorMessage();

                    logger.info("认证失败!!!!!!!!!!!");

             }

            }

            catch (Exception exc)

            {

               System.out.println(exc.getMessage());

          }

      }

        // 结束setServiceTicket单点登录代码

       

       /* System.out.println("开始获取用户名。。。");

        username = (String)request.getSessionContext().getAttribute("edu.yale.its.tp.cas.client.filter.user");

        System.out.println(username);

        System.out.println("结束获取用户名。。。");

 

        logger.info("登录用户为:"+username);*/

        return username;

    }

 

    public boolean isSessionValid(UserSession userSession,RequestContext request)

    {

        ServiceTicketValidator sv = new ServiceTicketValidator();

      String remoteUser =sv.getUser();  

        logger.info("RemoteUser为");

        logger.info(remoteUser);

        //user has since logged out

      if (remoteUser == null && userSession.getUserId() != SystemGlobals.getIntValue(ConfigKeys.ANONYMOUS_USER_ID))

        {

          return false;

      }

     

        // user has since logged in

      else if (remoteUser != null && userSession.getUserId() == SystemGlobals.getIntValue(ConfigKeys.ANONYMOUS_USER_ID))

        {

          return false;

      }

      // user has changed user

      else if (remoteUser != null && !remoteUser.equals(userSession.getUsername()))

        {

          return false;

      }   

      return true;

    }

}

 

通过http://localhost:8000/cas/login?service=http%3A%2F%2Flocalhost%3A8000%2Fjforum%2Fforums%2Fjforum.page%3Fmodule%3Dforums%26action%3Dlist登录成功后(admin/123),jforum显示的页面为admin的已登录页面,如果这时在当前浏览器输入配置了CAS的其他web应用,其他web应用不会弹出cas登录页面,因为cas已经登录过了。我做了一个测试,首先

打开一个新的浏览器窗口,输入一个配置了CAS的web应用地址,如http://localhost:8000/cms

,弹出cas登录窗口,输入admin/123,登录成功,这时候再输入http://localhost:8000/cas/login?service=http%3A%2F%2Flocalhost%3A8000%2Fjforum%2Fforums%2Fjforum.page%3Fmodule%3Dforums%26action%3Dlist,仍然出来一个CAS登录窗口,这好象不是我们所希望的,那么只好再把jforum的web.xml中的CAS过滤器配置好。

(五)当Jforum的web.xml中配置了CAS Filter时,如何实现单点登录类?

现在我们按(一)的说明配置好CAS Filter,重启tomcat,再次输入http://localhost:8000/cas/login?service=http%3A%2F%2Flocalhost%3A8000%2Fjforum%2Fforums%2Fjforum.page%3Fmodule%3Dforums%26action%3Dlist,反而后台报出认证失败的错误,Tomcat的控制台输出:

 

<cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>

        <cas:authenticationFailure code='INVALID_TICKET'>

                ticket 'ST-8-DWSSawgxWPwjjJwkScbIOqDcqR6eTUdZhwi-20' not recogni

zed

        </cas:authenticationFailure>

</cas:serviceResponse>

 

难道上面的CasUserSSO.java的ServiceTicketValidator的那段代码只适用于未配置CAS Filter的情况?还是因为配置了CAS Filter后,CAS自动做了ticket的验证后丢掉了ticket?所以CasUserSSO中取到的ticket已经过期?这个问题我没想明白,大家如果有清楚的话可以交流一下。

我现在想到一个问题,既然配了Cas Filter后,那么CAS登录后在session里有用户信息,为什么不直接从session中取呢?见上面的CasUserSSO.java,注释掉// 开始setServiceTicket单点登录代码和// 结束setServiceTicket单点登录代码之间的代码,使用下面的代码获得用户名:

 

        username = (String)request.getSessionContext().getAttribute("edu.yale.its.tp.cas.client.filter.user ");

 

这样岂不更直接!其中CAS登录成功后,配置了CAS Filter的Web应用的session都可以通过edu.yale.its.tp.cas.client.filter.user取得用户名,然后我们重新编译CasUserSSO.java,并启动tomcat,

这时再按下面的过程测试一下单点登录,首先新打开一个浏览器,输入http://localhost:8000/cms(此Web应用已配置了CAS),CAS登录窗口输入admin/123(cms应用的admin的口令和jforum的可以不同),登录成功后,再运行:

http://localhost:8000/jforum/forums/jforum.page?module=forums&action=list

不会再出来登录窗口了,此页面是系统管理员admin已登录的页面。

 

注意:如果CAS登录通过了一个jforum目前没有的帐户,则访问jforum时jforum会自动在数据库表(jforum_users)中插入一条新的记录,换句话说就是能自动注册,如果其他Web应用需要和jforum集成的话,只要配好了单点登录,就不需要担心其他应用的用户在jforum中注册的问题(不过自动注册只填写帐号名,其他字段还需要用户自己维护,或者编程实现从另外的应用数据库中将用户详细信息与jforum中的用户相关信息进行同步)。

(六)使用Cookie实现单点等录

 

由于CAS的配置比较复杂。在实际的企业应用中部署CAS比较麻烦,有的企业的应用服务器是WebSphere的,因此还要解决CAS如何在Websphere部署的问题,同时CAS的用户认证接口还要进行开发,CAS的性能能否满足注册用户信息量很大的电子商务网站?已有系统如何与CAS集成?等等很多问题需要我们考虑,如果我们只需要将Jforum论坛和电子商务平台集成起来,可以考虑采用Cookie进行单点登录的认证(我们项目只要求登录电子商务页面后进入论坛不用再登录而不是相反),用Cookie做单点登录的实现方式:

(1)电子商务平台登录成功后(不是基于CAS的,把用户名写到名为bbsUser的Cookie中)

(2)为保证安全性,Cookie只在电子商务应用服务器中有效(和Jforum在同一应用服务器运行,cookie.setPAth(“/”)),并且Cookie的MaxAge设置为-1,就是浏览器关闭后Cookie自动失效,另外session失效时也删除名为bbsUser的Cookie)

 

所以控制层和JSP中可参考下面代码创建Cookie:

        Cookie[] cookie1 = request.getCookies();  

         if(cookie1==null)

         {

             Cookie cookie = new Cookie("bbsUser", acegiUserName);

             cookie.setMaxAge(-1);   //负值表示浏览器关闭时cookie被删除,零值则是要删除该Cookie。

             cookie.setPath("/");

             response.addCookie(cookie);

         }

         else

         {

             for(int i=0; i< cookie1.length; i++)

             {  

                 String name = cookie1[i].getName();  

                 String value = cookie1[i].getValue();  

                 if(!name.equals("bbsUser"))  //已存在cookie则不需要增加cookie,否则增加cookie

                 {

                     Cookie cookie = new Cookie("bbsUser", acegiUserName);

                     cookie.setMaxAge(-1);   //负值表示浏览器关闭时cookie被删除,零值则是要删除该Cookie。

                     cookie.setPath("/"); //cookie只在同一应用服务器有效

                     response.addCookie(cookie);

                 }

             }

         }     

 

浏览器关闭,上面的cookie失效,如果session失效,则失效跳转或login.jsp要清除cookie,代码:

  //清除bbsUser的cookie

   Cookie cookie = new Cookie("bbsUser", "");

   cookie.setMaxAge(0);   //负值表示浏览器关闭时cookie被删除,零值则是要删除该Cookie。

   cookie.setPath("/");

   response.addCookie(cookie);

 

下面是在JForum中使用的CasCookieSSO.java,此代码从Cookie中读取名为bbsUser的Cookie作为用户名:

package com.iss.common.sso;

 

import net.jforum.context.RequestContext;

import net.jforum.entities.UserSession;

import net.jforum.util.preferences.ConfigKeys;

import net.jforum.util.preferences.SystemGlobals;

import org.apache.log4j.Logger;

import net.jforum.sso.*;

import java.util.*;

import java.net.*;

import javax.servlet.http.Cookie;

 

public class CasCookieSSO implements SSO

{

    static final Logger logger = Logger.getLogger(CasUserSSO.class.getName());

    public String authenticateUser(RequestContext request)

    {

        String username = null;

      String errorCode = null;

      String errorMessage = null;

      String xmlResponse = null;

 

        Cookie[] cookie = request.getCookies();  

        if(cookie == null)

        {

            //username = "guest";

        }

        else

        {

            for(int i=0; i< cookie.length; i++)

            {  

                String name = cookie[i].getName();  

                String value = cookie[i].getValue(); 

                if(name.equals("bbsUser"))

                {

                    username = value;

                    break; //退出循环

                }

            }

        }     

       

        logger.info("登录用户为:"+username);

        return username;

    }

 

    public boolean isSessionValid(UserSession userSession,RequestContext request)

    {

        return false;

        //说明:为什么在这里返回false,因为如果返回true的话,当cookie中的用户id变化后,再次访问jforum时,

        //jforum仍记忆上次使用的用户ID,当其他应用改变登录用户后,不能根据cookie中的bbsUser变量切换为新的用户,将返回值设置为false后问题解决。所以这里推荐直接返回false。

    }

}

使用CasCookieSSO时,注意更改Jforum的配置文件,sso.implementation = com.iss.common.sso. CasCookieSSO。

 

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/baozhengw/archive/2007/08/04/1726622.aspx

分享到:
评论

相关推荐

    jforum说明文档 源码解析 单点登录 jforum缓存

    Jforum是一款基于Java技术的开源论坛软件,它提供了丰富的社区功能,包括主题讨论、用户管理、权限控制、单点登录等。这款论坛系统以其稳定性和可扩展性而受到开发者的青睐。在深入理解Jforum的过程中,源码解析是至...

    JForum_SSO_-_JForum单点登陆原理与配置

    通过以上步骤,JForum就可以识别已登录主应用的用户,从而实现单点登录。这种方式简化了用户在多系统间的切换,提高了交互的便捷性。需要注意的是,为了保证安全性,应确保在传递和存储用户信息时采取适当的加密措施...

    Jforum二次开发实现SSO登陆(单点登录)

    实现了在一个网站实现多一个论坛的功能,在原网站登陆之后再Cookie保存一个值就可以实现单点登陆...我只是再原有网站可以实现单点登录到论坛.如果拿到资源不会用的也可以评论的时候带上QQ我会尽快联系。说出自己的问题

    JForum3 jforum java 开源论坛 论坛

    9. **API接口**:提供API接口,允许与其他系统集成,如SSO单点登录和第三方插件。 10. **丰富的插件和模块**:JForum3拥有众多插件和模块,可以扩展论坛功能,如积分系统、投票模块等。 在rafalsteil-jforum3-f4814...

    java开源论坛jforum

    Java开源论坛JForum是一款基于Java开发的讨论区平台,它为开发者提供了一个高效、功能...通过对JForum的源码学习,开发者可以掌握更多关于Web应用设计和实现的实用技巧,对于个人技术成长和职业发展都有着积极的影响。

    jforum2论坛源码

    通过研究jforum2源码,可以学习如何实现这些功能,并了解论坛系统的常见架构设计。 4. **性能测试**:JMeter的使用是测试jforum2性能的关键。开发者需要了解如何创建测试计划,定义线程组(模拟用户),设置采样器...

    jforum与web项目的整合(通过Cookie实现SSO)

    标题 "jforum与web项目的整合(通过Cookie实现SSO)" 涉及的是将开源的JForum论坛系统与其他Web应用程序进行集成,并利用Cookie技术实现单点登录(Single Sign-On,简称SSO)。SSO允许用户在一个应用系统中登录后,...

    Jforum论坛数据库架构

    Jforum是一款基于Java语言开发的开源论坛系统,其强大的功能和灵活性使其在互联网社区建设中受到广泛欢迎。数据库架构是任何Web应用程序的核心部分,对于Jforum论坛而言也不例外。一个良好的数据库架构设计能够确保...

    Jforum相关文档和PPT

    Jforum是一款基于Java技术的开源论坛系统,以其高效、安全和可扩展性受到...通过深入学习和理解这些知识点,无论是开发者还是管理员,都能够更好地管理和维护Jforum论坛,提升用户体验,保障系统的稳定性和安全性。

    jforum开源的论坛文档

    ### jforum开源论坛的核心知识点 #### 一、jForum简介 jForum是一款基于Java语言编写的开源论坛系统,它提供了一套完整的社区解决方案,适用于构建各类在线社区与论坛。jForum以其灵活的架构、丰富的功能及优秀的...

    JForum论坛系统

    JForum是一款基于Java技术的开源论坛软件,主要采用JSP(JavaServer Pages)作为前端展示和Servlet作为后端处理,搭配MySQL数据库进行数据存储。这款论坛系统设计灵活,易于扩展,提供了丰富的功能,适用于构建社区...

    利用JForum创建论坛

    【JForum论坛创建详解】 JForum是一款知名的开源论坛软件,具备多语言支持,包括简体中文,虽然管理界面并未完全汉化。它以其强大的功能、优雅的界面以及清晰的代码结构,成为二次开发的理想选择。JForum基于BSD...

    jforum开源论坛 官方源代码(2.1.9)

    JForum是一款基于Java技术的开源论坛系统,以其高效、稳定和易用性在开源社区中受到广泛关注。本次我们探讨的是JForum的2.1.9版本,这是一个经过众多开发者共同努力优化的版本,包含了丰富的功能和改进。本文将深入...

    jforum开源论坛

    **JForum开源论坛详解** JForum是一款基于Java技术的开源论坛系统,专为构建互动社区而设计。它提供了丰富的功能,如用户管理、版块创建、主题发布、回帖讨论等,适合各种类型的网站集成,无论是企业级应用还是个人...

    Java论坛系统 JForum

    Java论坛系统 JForum 是一个基于Java技术开发的开源讨论平台,专为构建在线社区和互动论坛而设计。JForum以其高效、稳定和可扩展性著称,采用MVC(Model-View-Controller)架构模式,支持多语言,提供丰富的功能,如...

    jforum论坛图片资源

    用于配置中文jforum,里面包含各种语言的图片文件,将其中的zh_CN目录复制到jforum安装目录下的templates\default\images。就可以显示中文图片

    jforum 源码

    **正文** JForum是一款基于Java...通过对JForum源码的深度学习,开发者不仅可以掌握FreeMarker的使用,还能了解一个完整的Web应用是如何设计和实现的,对于提升Java Web开发技能和理解大型项目结构有着极大的帮助。

    jforum3源代码 数据库

    3. **数据访问层(Data Access Layer)**:通过DAO(Data Access Object)接口和实现,与数据库进行交互。 4. **模型对象(Model Objects)**:表示论坛中的实体,如用户、帖子、板块等。 5. **配置文件**:如`forum...

Global site tag (gtag.js) - Google Analytics