利用Struts结合Jbuilder7、MySql建立Web站点(2)--分页显示
作者:Sailing(蓝色虾)
本程序全部源代码:vod.zip
介绍:
本篇接着第一篇的内容,继续进行VOD网站的制作(第一篇《利用Struts结合Jbuilder7、MySql建立Web站点(1)--连接数据库》),
当需要将数据库中的大量内容供用户浏览的时候,我们一般采用两种方法,第一种很简单,一次性将数据库中的内容读出,接着全部
显示在网页上,这种方法在数据量较小的时候一般采用;还有一种方法就是分页显示,也是现在各大网站普遍采用的方式,关于分页
的方法多种多样,我这里采用的是普遍使用的采取移动数据库指针的方法。
建立PageInfo Bean
这个Bean的任务就是储存关于分页需要的所有信息,包括总共含有的页数,含有的纪录总数,当前的页数,上一页的页数,下一页的
页数,将这五条信息包含在同一个bean中将会给以后在jsp页面中的编程带来很大的方便,因为目前有许多网站将目前的页数,上一页
的页数和下一页的页数不放在bean中,而是在jsp页面通过当前的页数分别加上1和减去1得到,虽然这样很方便,但是这样做将会在Jsp
页面中产生逻辑的运算,破坏了MVC的规则,以上将5个变量放入一个bean的编程方法只是我的个人习惯,如果大家觉得有不妥的地方请多多指教。 PageInfo的代码如下:
package vod.model;
import java.util.Vector;
public class PageInfo {
private int totalPage;//总共有多少页
private int resultCount;//总共有多少条纪录
private int page;//目前的页数
private int previousPage;//上一页
private int nextpage;//下一页
public void setTotalPage(int totalPage){
this.totalPage=totalPage;
}
public int getTotalPage(){
return totalPage;
}
//-------------------------------------------
public void setResultCount(int count){
this.resultCount=count;
}
public int getResultCount(){
return resultCount;
}
//-------------------------------------------
public void setPage(int page){
this.page=page;
}
public int getpage(){
return page;
}
//-------------------------------------------
public void setPreviousPage(int page){
this.previousPage=page;
}
public int getPreviousPage(){
return (this.page-1);
}
//-------------------------------------------
public void setNextPage(int page){
this.nextpage=page;
}
public int getNextPage(){
return (this.page+1);
}
//-------------------------------------------
/**
* 根据传来的数组生成一个PageInfo对象
* 我们约定数组中的index为0的为总页数
* index为1的纪录总数
* @param info
* @return
*/
public static PageInfo load(int[] info){
PageInfo pageinfo =new PageInfo();
int intValue=0;
intValue=info[0];
if(intValue > 0)
pageinfo.setTotalPage(intValue);
intValue=info[1];
if(intValue > 0)
pageinfo.setResultCount(intValue);
return pageinfo;
}
}
注意这里的load()方法中的int数组,我们约定数组中的第一个元素为总页数,第二个元素为纪录总数。这里的getPreviousPage()
方法没有直接返回previousPage,而是根据page的值减去1得到previousPage是为了以后调用的方便。
数据库的分页
我们在进行分页的读取之前我们首先要做的事情就是确定所要操作的数据库中的内容按照我们需要的每页显示多少数据量
可以分为几页,总共有多少数据。下面我们来看看这个分页代码(EvaluateDateBase.java)的实现:
package vod.model;
import java.sql.Connection;
import org.gjt.mm.mysql.jdbc2.ResultSet;
import java.sql.PreparedStatement;
import java.sql.Statement;
import java.sql.SQLException;
public class EvaluateDateBase {
/**
*根据方法中的数据表的名称,连接,每页出现的纪录数方法返回一个PageInfo的实例
*/
public static PageInfo getPageInfo(String datebase,Connection conn,int pageSize) throws SQLException{
int totalPage=0;
int resultCount=0;
int[] info=new int[2];
String sql="";
if(conn==null)
throw new SQLException("No Conn in EvaluateDateBase");
ResultSet rsCount=null;
PreparedStatement psmt=null;
sql="select count(*) from "+datebase;//根据数据库的名字得到相对应的SQL语句
try{
psmt=conn.prepareStatement(sql);
rsCount=(ResultSet)psmt.executeQuery();
rsCount.next();
resultCount=rsCount.getInt(1);
rsCount.close();
}catch(SQLException e){
e.printStackTrace();
}
totalPage = (resultCount+pageSize-1) / pageSize;//统计总页数
//还记得我们的约定吗?
// index为0的为总页数,index为1的为纪录总数
info[0]=totalPage;
info[1]=resultCount;
PageInfo pageinfo=PageInfo.load(info);
return pageinfo;
}
}
这里我们使用了sql="select count(*) from "+datebase; 来得到对应的SQL语句,根据这个SQL语句得到的结果集通过getInt(1)
将得到这个结果集含有多少条纪录。并且(resultCount+pageSize-1) / pageSize得到按照需要的每页显示的纪录数得到的总页
数,可能初学者会疑惑为什么不直接用结果总数除以每页需要的结果数得到总页数呢,这样是因为如果含有的记录数不能被整除
的话,那么统计得到的总页数将会少一页,按照上面的方法计算将会得到正确的数值,有兴趣的话大家可以算算,当然也可以通过
另外一种方法实现就是如果不能整除就加上1的方法实现。最后将得到的总页数和总纪录数放入一个PageInfo实例中以便以后调用。
取得所有关于足球的影片,并按照需要的范围取得合适的LinkedList
要取得分页所需要的数据库中的内容所需要的代码将在这儿出现,我们的分页原理很简单,举个例子:目前我们设定每一页只显示10
条纪录,那么假如用户要取得第2页的内容,那么就是第11-20条纪录,我们就先将数据库的游标移到第10条记录上,然后通过while
和next()结合的方法取得第11-20 条的数据。然后读取每一条纪录,通过Football的load()将纪录中的数据库的字段与Football Bean
中的值匹配并将其放入一个LinkedList中。
代码如下(MoreFootball.java):
package vod.model;
import java.sql.Connection;
import org.gjt.mm.mysql.jdbc2.ResultSet;
import java.sql.PreparedStatement;
import java.sql.Statement;
import java.sql.SQLException;
import java.util.LinkedList;
public class MoreFootball {
Connection conn;
public void setConn(Connection conn){
this.conn=conn;
}
public LinkedList getFootballList(int page,int pageSize) throws SQLException{
LinkedList footballList;
if(conn==null)
throw new SQLException("No Connection in MoreFootball");
PreparedStatement pstmt = null;
ResultSet rs = null;
footballList=new LinkedList();
try{
pstmt = conn.prepareStatement("select * from football order by date desc");
rs = (ResultSet)pstmt.executeQuery();
//根据目前需要显示的页数和每一页要求显示的纪录条数移动数据库的指针
int i = (page-1) * pageSize;
//由于不能定位到0这个位置
if(i!=0)
rs.absolute(i);//如果i为10,那么数据库的指针将会移动到第十条数据上
/*
for(int j=0;j<i;j++)
rs.next();
*/
int ii=0;
while(rs.next() && ii<pageSize){
footballList.add(Football.load(rs));
ii++;
}
}catch(SQLException e){
e.printStackTrace();
}
finally {
if (rs != null)
rs.close();
if (pstmt != null)
pstmt.close();
}
return footballList;
}
}
注意这里被注释掉的代码:
/*
for(int j=0;j<i;j++)
rs.next();
*/
如果你的JDBC驱动程序不支持absolute()这个方法,那么这个for循环竟是一个很不错的替代品。
MoreFootballAction的编写,这里PageInfo将起到关键性的作用
这个action的工作流程为,首先从web.xml文件中取得关于每一页显示多少条纪录的信息,在web.xml中通过
<context-param>
<param-name>pageSize</param-name>
<param-value>10</param-value>
</context-param>
定义,定义每页显示纪录10条,这个数值可以通过Servelet中的context的getInitParameter()方法取得。接着得到用户
需要第几页的请求(这个请求的页数将会作为参数跟在jsp中的链接后面),并对用户请求的页数进行处理,保证其值在
合理的范围之内;然后通过EvaluateDateBas的静态方法getPageInfo()获得关于所要操作的数据表的含有总共有多少条纪录
和总共有多少页的信息的PageInfo实例,接着将刚刚得到的用户请求的页数信息与得到的这个实例中的总页数进行比较,如
果用户请求的页数大于总页数,那么将用户请求的页数等于总页数,如果用户请求的页数小于0的话,那么就将用户请求的页
数等于1;最后将调整过的当前用户请求的页数传入PageInfo的实例,以便于后面获得用户请求的页数的前一页和后一页的页
数,程序的最后根据用户请求的页数和每页显示多少条目传入getFootballList()得到包含有相应条目的LinkedList,并且将
其放入session,便于以后在页面中调用。
代码如下:
package vod.controller;
import vod.model.PageInfo;
import vod.model.MoreFootball;
import vod.model.EvaluateDateBase;
import java.io.IOException;
import java.util.LinkedList;
import java.util.Locale;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionError;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionServlet;
import org.apache.struts.util.MessageResources;
import java.sql.Connection;
import java.sql.SQLException;
import javax.sql.DataSource;
public class MoreFootballAction extends Action {
Connection connection;
LinkedList footballList;
public ActionForward perform(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException{
ActionErrors errors = new ActionErrors();
HttpSession session = request.getSession();
int page=0;//目前需要的页数
int pageSize=0;//每页显示多少条数据
PageInfo footballPageInfo=null;//关于页数的相关信息
String tempPage;
//从web.xml文件中取得每页显示的条目数(我设置为10条)
pageSize=Integer.parseInt((String)servlet.getServletContext().getInitParameter("pageSize"));
//如果没有明确页数那么默认为第一页
tempPage=request.getParameter("page");
if(tempPage==null)
tempPage="1";
page=Integer.parseInt(tempPage);
try {
DataSource dataSource =servlet.findDataSource(null);
connection =dataSource.getConnection();
//检查session中是否已经存在了PageInfo,如果没有就执行查询,并且将footballPageInfo
//放入session之中
//如果已经存在的话直接从session中读取
if(session.getAttribute("footballPageInfo")==null){
//参数分别为数据表名称,连接,每一页显示多少条目
footballPageInfo=EvaluateDateBase.getPageInfo("football",connection,pageSize);
}else{
footballPageInfo=(PageInfo)session.getAttribute("footballPageInfo");
}
if(page > footballPageInfo.getTotalPage()){
page=footballPageInfo.getTotalPage();
}else if(page < 0){
page=1;
}
//设置footballPageInfo中的上一页和下一页的数值
footballPageInfo.setPage(page);
//将footballPageInfo放入session
session.setAttribute("footballPageInfo",footballPageInfo);
footballList=new LinkedList();
MoreFootball morefootball=new MoreFootball();
morefootball.setConn(connection);//设置数据的连接
//根据需要的页数和每页显示的页数条数得到LinkedList
footballList=morefootball.getFootballList(page,pageSize);
if (footballList==null) {
saveErrors(request, errors);
return (new ActionForward("No footballList in vod.controller.MoreFootallAction"));
}
session.setAttribute("footballList",footballList);//将取得的footballList放入session
//do what you wish with myConnection
} catch (SQLException sqle) {
getServlet().log("Connection.process", sqle);
} finally {
//enclose this in a finally block to make
//sure the connection is closed
if(connection!=null)
try {
connection.close();
} catch (SQLException e) {
getServlet().log("Connection.close", e);
}
}
return (mapping.findForward("success"));
}
}
action.xml和struts-config.xml文件的配置
这里将不再阐述,请参考第一篇《利用Struts结合Jbuilder7、MySql建立Web站点(1)--连接数据库》
struts-config.xml:
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE struts-config PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 1.0//EN"
"http://jakarta.apache.org/struts/dtds/struts-config_1_0.dtd">
<!--
This is the Struts configuration file for the example application,
using the proposed new syntax.
NOTE: You would only flesh out the details in the "form-bean"
declarations if you had a generator tool that used them to create
the corresponding Java classes for you. Otherwise, you would
need only the "form-bean" element itself, with the corresponding
"name" and "type" attributes.
-->
<struts-config>
<!-- ========== Data Source Configuration =============================== -->
<data-sources>
<data-source>
<set-property property="autoCommit"
value="false"/>
<set-property property="description"
value="Data Source Configuration"/>
<set-property property="driverClass"
value="org.gjt.mm.mysql.Driver"/>
<set-property property="maxCount"
value="200"/>
<set-property property="minCount"
value="20"/>
<set-property property="password"
value="sailing"/>
<set-property property="url"
value="jdbc:mysql://localhost/gdmovie"/>
<set-property property="user"
value="DateBase"/>
</data-source>
</data-sources>
<!-- ========== Form Bean Definitions =================================== -->
<form-beans>
<!-- Football form bean -->
<form-bean name="footballForm"
type="vod.model.footballForm"/>
<!-- Fun form bean -->
<form-bean name="funForm"
type="vod.model.funForm"/>
<!-- Movie form bean -->
<form-bean name="movieForm"
type="vod.model.movieForm"/>
<!-- MTV form bean -->
<form-bean name="mtvForm"
type="vod.model.mtvForm"/>
</form-beans>
<!-- ========== Global Forward Definitions ============================== -->
<global-forwards>
<forward name="welcome" path="/welcome.do"/>
</global-forwards>
<!-- ========== Action Mapping Definitions ============================== -->
<action-mappings>
<!-- Enter into welcome Page -->
<action path="/welcome"
type="vod.controller.DisplayWelcomeAction">
<forward name="success" path="/welcome.jsp"/>
</action>
<!-- Enter into morefootball Page -->
<action path="/morefootball"
type="vod.controller.MoreFootballAction">
<forward name="success" path="/morefootball.jsp"/>
</action>
<!-- Enter into viewfootball Page -->
<action path="/viewfootball"
type="vod.controller.ViewFootballAction">
<forward name="success" path="/viewfootball.jsp"/>
</action>
</action-mappings>
</struts-config>
action.xml:
<action-mappings>
<!-- Global Forward Declarations -->
<forward name="welcome" path="/welcome.do"/>
<!-- Process a user logon -->
<action path="/welcome"
actionClass="vod.controller.DisplayWelcomeAction">
<forward name="success" path="/welcome.jsp"/>
</action>
<action path="/morefootball"
actionClass="vod.controller.MoreFootballAction">
<forward name="success" path="/morefootball.jsp"/>
</action>
<action path="/viewfootball"
actionClass="vod.controller.ViewFootballAction">
<forward name="success" path="/viewfootball.jsp"/>
</action>
</action-mappings>
Jsp页面
welcome.jsp:将在这个页中加入更多足球这个链接,并且调用MoreFootballAction并且指定取第一页。
代码如下:
<%@ page contentType="text/html; charset=GB2312" %>
<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
<%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %>
<html>
<head>
<title>
welcome
</title>
</head>
<body>
<table width="694" border="1" cellspacing="0" cellpadding="0">
<tr>
<td width="70"><div align="center">id</div></td>
<td width="110"><div align="center">footname</div></td>
<td width="82"><div align="center">viewURL</div></td>
<td width="92"><div align="center">downURL</div></td>
<td width="48"><div align="center">clicks</div></td>
<td width="41"><div align="center">sort</div></td>
<td width="40"><div align="center">intro</div></td>
<td width="66"><div align="center">commend</div></td>
<td width="61"><div align="center">date</div></td>
<td width="33"><div align="center">bad</div></td>
<td width="51"><div align="center">length</div></td>
</tr>
<logic:iterate id="football" name="footballTop">
<tr>
<td><div align="center"><bean:write name="football" property="id"/></div></td>
<td><div align="center"><bean:write name="football" property="footballName"/></div></td>
<td><div align="center"><bean:write name="football" property="viewURL"/></div></td>
<td><div align="center"><bean:write name="football" property="downURL"/></div></td>
<td><div align="center"><bean:write name="football" property="clicks"/></div></td>
<td><div align="center"><bean:write name="football" property="sort"/></div></td>
<td><div align="center"><bean:write name="football" property="intro"/></div></td>
<td><div align="center"><bean:write name="football" property="commend"/></div></td>
<td><div align="center"><bean:write name="football" property="date"/></div></td>
<td><div align="center"><bean:write name="football" property="bad"/></div></td>
<td><div align="center"><bean:write name="football" property="length"/></div></td>
</tr>
</logic:iterate>
</table>
<html:link page="/morefootball.do?page=1">更多足球</html:link>
<br>
<table width="694" border="1" cellspacing="0" cellpadding="0">
<tr>
<td width="70"><div align="center">id</div></td>
<td width="110"><div align="center">funname</div></td>
<td width="82"><div align="center">viewURL</div></td>
<td width="92"><div align="center">downURL</div></td>
<td width="48"><div align="center">clicks</div></td>
<td width="41"><div align="center">sort</div></td>
<td width="40"><div align="center">intro</div></td>
<td width="66"><div align="center">commend</div></td>
<td width="61"><div align="center">date</div></td>
<td width="33"><div align="center">bad</div></td>
<td width="51"><div align="center">length</div></td>
</tr>
<logic:iterate id="fun" name="funTop">
<tr>
<td><div align="center"><bean:write name="fun" property="id"/></div></td>
<td><div align="center"><bean:write name="fun" property="funName"/></div></td>
<td><div align="center"><bean:write name="fun" property="viewURL"/></div></td>
<td><div align="center"><bean:write name="fun" property="downURL"/></div></td>
<td><div align="center"><bean:write name="fun" property="clicks"/></div></td>
<td><div align="center"><bean:write name="fun" property="sort"/></div></td>
<td><div align="center"><bean:write name="fun" property="intro"/></div></td>
<td><div align="center"><bean:write name="fun" property="commend"/></div></td>
<td><div align="center"><bean:write name="fun" property="date"/></div></td>
<td><div align="center"><bean:write name="fun" property="bad"/></div></td>
<td><div align="center"><bean:write name="fun" property="length"/></div></td>
</tr>
</logic:iterate>
</table>
<br>
<table width="694" border="1" cellspacing="0" cellpadding="0">
<tr>
<td width="70"><div align="center">id</div></td>
<td width="110"><div align="center">moviename</div></td>
<td width="82"><div align="center">viewURL</div></td>
<td width="92"><div align="center">downURL</div></td>
<td width="48"><div align="center">clicks</div></td>
<td width="41"><div align="center">sort</div></td>
<td width="40"><div align="center">intro</div></td>
<td width="66"><div align="center">commend</div></td>
<td width="61"><div align="center">date</div></td>
<td width="33"><div align="center">bad</div></td>
<td width="51"><div align="center">length</div></td>
</tr>
<logic:iterate id="movie" name="movieTop">
<tr>
<td><div align="center"><bean:write name="movie" property="id"/></div></td>
<td><div align="center"><bean:write name="movie" property="movieName"/></div></td>
<td><div align="center"><bean:write name="movie" property="viewURL"/></div></td>
<td><div align="center"><bean:write name="movie" property="downURL"/></div></td>
<td><div align="center"><bean:write name="movie" property="clicks"/></div></td>
<td><div align="center"><bean:write name="movie" property="sort"/></div></td>
<td><div align="center"><bean:write name="movie" property="intro"/></div></td>
<td><div align="center"><bean:write name="movie" property="commend"/></div></td>
<td><div align="center"><bean:write name="movie" property="date"/></div></td>
<td><div align="center"><bean:write name="movie" property="bad"/></div></td>
<td><div align="center"><bean:write name="movie" property="length"/></div></td>
</tr>
</logic:iterate>
</table>
<br>
<table width="694" border="1" cellspacing="0" cellpadding="0">
<tr>
<td width="70"><div align="center">id</div></td>
<td width="110"><div align="center">mtvname</div></td>
<td width="82"><div align="center">viewURL</div></td>
<td width="92"><div align="center">downURL</div></td>
<td width="48"><div align="center">clicks</div></td>
<td width="41"><div align="center">sort</div></td>
<td width="40"><div align="center">intro</div></td>
<td width="66"><div align="center">commend</div></td>
<td width="61"><div align="center">date</div></td>
<td width="33"><div align="center">bad</div></td>
<td width="51"><div align="center">length</div></td>
</tr>
<logic:iterate id="mtv" name="mtvTop">
<tr>
<td><div align="center"><bean:write name="mtv" property="id"/></div></td>
<td><div align="center"><bean:write name="mtv" property="mtvName"/></div></td>
<td><div align="center"><bean:write name="mtv" property="viewURL"/></div></td>
<td><div align="center"><bean:write name="mtv" property="downURL"/></div></td>
<td><div align="center"><bean:write name="mtv" property="clicks"/></div></td>
<td><div align="center"><bean:write name="mtv" property="sort"/></div></td>
<td><div align="center"><bean:write name="mtv" property="intro"/></div></td>
<td><div align="center"><bean:write name="mtv" property="commend"/></div></td>
<td><div align="center"><bean:write name="mtv" property="date"/></div></td>
<td><div align="center"><bean:write name="mtv" property="bad"/></div></td>
<td><div align="center"><bean:write name="mtv" property="length"/></div></td>
</tr>
</logic:iterate>
</table>
</body>
</html>
morefootball.jsp:这里的<bean:write name="footballPageInfo" property="nextPage"/>和
<bean:write name="footballPageInfo" property="previousPage"/>经直接调用bean中的
相应get方法中的page+1和page-1
代码如下:
<%@ page contentType="text/html; charset=GB2312" %>
<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
<%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %>
<html>
<head>
<title>
morefootball
</title>
</head>
<body>
<table width="600" border="0" cellspacing="0" cellpadding="0">
<tr>
<td><div align="center">名字</div></td>
<td><div align="center">点击次数</div></td>
<td><div align="center">类型</div></td>
<td><div align="center">长度</div></td>
<td><div align="center">id</div></td>
</tr>
<logic:iterate id="football" name="footballList">
<tr>
<td><div align="center"><a href="viewfootball.do?id=<bean:write name="football" property="id"/>" target="_blank"><bean:write name="football" property="footballName"/></a></div></td>
<td><div align="center"><bean:write name="football" property="clicks"/></div></td>
<td><div align="center"><bean:write name="football" property="sort"/></div></td>
<td><div align="center"><bean:write name="football" property="length"/></div></td>
<td><div align="center"><bean:write name="football" property="id"/></div></td>
</tr>
</logic:iterate>
<tr>
<td colspan="5"><div align="center"><a href="/morefootball.do?page=1">首页</a> <a href="/morefootball.do?page=<bean:write name="footballPageInfo" property="previousPage"/>">上一页</a>
<a href="/morefootball.do?page=<bean:write name="footballPageInfo" property="nextPage"/>">下一页</a> <a href="/morefootball.do?page=<bean:write name="footballPageInfo" property="totalPage"/>">末页</a> 共有<bean:write name="footballPageInfo" property="totalPage"/>页 目前为<bean:write name="footballPageInfo" property="page"/>页 共有<bean:write name="footballPageInfo" property="resultCount"/>条纪录</div></td>
</tr>
</table>
</body>
</html>
结尾:
其实还有一部分为点击足球影片的名字后谈弹出一个新的窗口,包含了相应足球影片的信息,由于内容重复,故不再写了
,包含在源代码中。
下一篇文章将是关于FormBean的使用和数据库的插入和删除。
本程序全部源代码:vod.zip
我写着篇文章的目的只由于当时在网上只能找到很少的关于Struts的中文资料,特别来火,干脆自己就写了一篇。
真心希望网上关于Java方面的中文资料能够越来越多。
在使用Tomacat是产生了 在JB7中配合tomact+mysql使用连接池的问题,请大家帮忙解答,多谢了。
关于作者:
Sailing,就读于南京工业大学工商管理专业,爱好Java编程,熟悉网站制作,真诚希望与大家进行交流。
工作室:Mars Studio