Day7 - Struts2 - jQuery

1. Struts2 與 Servlet

  • 封裝 Servlet 的大部分功能,Struts2 是 Servlet 的上層
  • Struts2 能做的 Servlet 都能做纫塌,反之不行
  • Struts2 框架提供了 action诊县,服務(wù)器資源增添了 action
  • Struts2 在 web.xml 中配置過(guò)濾器管理 action

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">
    <filter>
        <filter-name>struts2</filter-name>
        <!--struts2框架提供的核心類過(guò)濾器,拿到參數(shù)措左,封裝對(duì)象-->
        <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
    </filter>


    <!--注釋掉可以過(guò)濾所有鏈接部分-->
    <!--<filter-mapping>-->
    <!--<filter-name>struts2</filter-name>-->
    <!--<url-pattern>/*</url-pattern>-->
    <!--</filter-mapping>-->

    <filter-mapping>
        <filter-name>struts2</filter-name>
        <!--通過(guò) .action -->
        <url-pattern>*.action</url-pattern>
        <dispatcher>REQUEST</dispatcher>
        <dispatcher>FORWARD</dispatcher>
    </filter-mapping>

    <filter-mapping>
        <filter-name>struts2</filter-name>
        <!--通過(guò) .jsp -->
        <url-pattern>*.jsp</url-pattern>
    </filter-mapping>

</web-app>
public class StrutsPrepareAndExecuteFilter implements StrutsStatics, Filter {}
  • struts2 框架核心類 StrutsPrepareAndExecuteFilter 實(shí)現(xiàn) Servlet 提供的 Filter 接口
  • web.xml 中 <filter-mapping> 目前只允許通過(guò) .action.jsp 后綴的鏈接

jar 包 鏈接:http://pan.baidu.com/s/1nvkLAR3 密碼:vze1

2. 攔截器

  • 攔截訪問(wèn) action 的請(qǐng)求
  • 給這個(gè) action 加入新的豐富功能(上傳依痊、參數(shù)自動(dòng)接收、類型自動(dòng)轉(zhuǎn)換等等)
  • 攔截之后怎披,在 intercept 函數(shù) 調(diào)用 invoke 方法 才真正啟動(dòng) action

MyInterceptor.java

package com.shuai.web.interceptor;

import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.Interceptor;

/**
 * Created by shuai
 * on 2017/8/21.
 */
public class MyInterceptor implements Interceptor {

    @Override
    public void destroy() {
        System.out.println("MyInterceptor destroy...");
    }

    @Override
    public void init() {
        System.out.println("MyInterceptor init...");
    }

    @Override
    public String intercept(ActionInvocation actionInvocation) throws Exception {
        System.out.println("before...");
        String s = actionInvocation.invoke(); // 真正調(diào)用action方法 顯示toIndex方法中的打印
        System.out.println("after...");
        return s;
    }
}

struts.xml 路徑固定胸嘁,放在 src 下

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE struts PUBLIC
        "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
        "http://struts.apache.org/dtds/struts-2.3.dtd">

<struts>
    <package name="cms-package" extends="struts-default">
        <interceptors>
            <interceptor name="auth" class="com.shuai.web.interceptor.MyInterceptor"></interceptor>
            <!--攔截器棧-->
            <interceptor-stack name="cmsAuthStack">
                <interceptor-ref name="auth"></interceptor-ref>
                <interceptor-ref name="defaultStack"></interceptor-ref>
            </interceptor-stack>
        </interceptors>

        <global-results>
            <result name="toLogin">
                /WEB-INF/jsp/login.jsp
            </result>
        </global-results>
    </package>
</struts>

IndexAction.java 在 @Action 注解中加上攔截器

package com.shuai.web.action;

import com.opensymphony.xwork2.ActionSupport;
import org.apache.struts2.convention.annotation.Action;
import org.apache.struts2.convention.annotation.InterceptorRef;
import org.apache.struts2.convention.annotation.Result;

// 繼承 ActionSupport
public class IndexAction extends ActionSupport {
    @Action(value = "/toIndex",
            results = {@Result(location = "/index.jsp")}, // 默認(rèn)的SUCCESS,不用指明name
            // 配置攔截器凉逛,可以攔下頁(yè)面性宏,做一些處理再顯示
            interceptorRefs = {@InterceptorRef("cmsAuthStack")}
    )
    public String toIndex() {
        System.out.println("in index...");
        return SUCCESS; // Action 接口中 String SUCCESS = "success";
    }
}

3. 前端瀏覽器與后端數(shù)據(jù)庫(kù)的交互過(guò)程 - 分層開(kāi)發(fā)

Browser:前端頁(yè)面點(diǎn)擊超鏈接,跳轉(zhuǎn)到 Action 鏈接状飞;

index.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>主頁(yè)</title>

    <link rel="stylesheet" >

    <script src="frameworks/jquery-2.1.4/jquery.min.js"></script>
    <script src="js/index.js"></script>
</head>
<body style="margin-left: 10px">

<h1>Ah! We are here</h1>

<ul>
    <li><a class="ff" href="javascript:void(0);">顯示用戶信息</a></li>
    <li><a class="ff" href="javascript:void(0);">添加用戶信息</a></li>
</ul>

<div class="below"></div>

</body>
</html>

通過(guò) jQuery 的 load 方法實(shí)現(xiàn)在 index.jsp 頁(yè)面中異步加載其他 jsp 頁(yè)面

index.js

$(function () {

    // class選擇器
    $(".ff").click(function () {
        console.log("in ff...");
        switch ($(this).text()) {
            case "顯示用戶信息":
                // 異步請(qǐng)求 Ajax
                // load 方法內(nèi)部方式實(shí)現(xiàn)了 Ajax 在同一個(gè)頁(yè)面的 div 中加載另一個(gè)頁(yè)面
                // 選中 below 這個(gè) div 顯示 toShowUser.action 對(duì)應(yīng)頁(yè)面的內(nèi)容
                $(".below").load("toShowUser.action?parentDir=jsp&specifyUrl=showUser.jsp");
                break;
            case "添加用戶信息":
                // 同上
                $(".below").load("toAddUser.action?parentDir=jsp&specifyUrl=addUser.jsp");
                break;
            default:
                break;
        }
    });

});
Action:每個(gè) Action 對(duì)應(yīng) UserAction 類中的一個(gè)函數(shù)毫胜,比如 toShowUser()书斜,函數(shù)內(nèi)調(diào)用 service 接口實(shí)現(xiàn)特定功能,比如 service.findAllUsers()指蚁;

UserAction 類中的 toShowUser 函數(shù)

@Action(value = "/toShowUser", results = {
        @Result(location = "/WEB-INF/jsp/showUser.jsp"),
        @Result(name = ERROR, location = "/index.jsp", type = "redirectAction")
})
public String toShowUser() throws ServiceException {

    System.out.println("show user...");

    List<User> list = service.findAllUsers(); // service 接口
    requestMap.put("list", list); // 通過(guò)UserAction類實(shí)現(xiàn)RequestAware接口傳值

    return SUCCESS; // Action 接口 String SUCCESS = "success";
}
  • @Action 注解中 @Result 默認(rèn)的是 SUCCESS菩佑,不用指明,但是 ERROR 要指明
  • SUCCESS = String "success"
Service:與 Service 接口同時(shí)存在一個(gè) Service 實(shí)現(xiàn)類 UserServiceImpl凝化,該實(shí)現(xiàn)類調(diào)用 UserDao 的方法完成與數(shù)據(jù)庫(kù)的交互稍坯;

UserServiceImpl 類實(shí)現(xiàn) service 接口方法

package com.shuai.service;

import com.shuai.bean.User;
import com.shuai.common.ServiceException;
import com.shuai.dao.UserDao;

import java.util.List;

// UserService 的實(shí)現(xiàn)類
public class UserServiceImpl implements UserService {

    private UserDao dao = new UserDao();

    @Override
    public void registerUser(User user) throws ServiceException {
        User u = dao.findUserByName(user.getName()); // 查找用戶 調(diào)用 UserDao 方法
        if (u != null) {
            throw new ServiceException("user exist!");
        } else {
            dao.saveUser(user); // 存入數(shù)據(jù)庫(kù) 調(diào)用 UserDao 方法
        }
    }

    @Override
    public List<User> findAllUsers() throws ServiceException {
        return dao.findAllUsers(); // 查找所有用戶 調(diào)用 UserDao 方法
    }
}
dao:定義了與數(shù)據(jù)庫(kù)交互的方法,通過(guò) Hibernate 實(shí)現(xiàn)搓劫;

UserDao 類

package com.shuai.dao;

import com.shuai.bean.User;
import com.shuai.common.HibernateSessionFactory;
import org.hibernate.Criteria;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.criterion.Restrictions;

import java.util.List;

/**
 * Created by shuai
 * on 2017/8/21.
 */
public class UserDao {

    // 保存用戶
    public void saveUser(User user) {
        Session session = HibernateSessionFactory.getSession();
        Transaction ts = session.beginTransaction();
        session.save(user); // 事物內(nèi)容
        ts.commit();
    }


    // 查詢用戶
    public User findUserByName(String name) {

        Session session = HibernateSessionFactory.getSession();
        Criteria criteria = session.createCriteria(User.class);

        List<User> list = criteria.add(Restrictions.eq("name", name)).list();

        if (list.size() == 0) {
            return null;
        } else {
            return list.get(0);
        }
    }

    // 查詢所有用戶
    public List<User> findAllUsers() {
        Session session = HibernateSessionFactory.getSession();
        SQLQuery sqlQuery = session.createSQLQuery("SELECT * FROM TBL_USER");
        sqlQuery.addEntity(User.class); // hibernate.cfg文件注冊(cè)了映射類
        return sqlQuery.list();
    }
}
db:通過(guò) hibernate.cfg.xml 文件配置好瞧哟,就可以前后端交互了。
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">

<hibernate-configuration>

    <session-factory>
        <property name="connection.username">briup</property>
        <property name="connection.password">briup</property>
        <property name="connection.url">
            jdbc:oracle:thin:@172.20.10.2:1521:XE
        </property>
        <property name="connection.driver_class">
            oracle.jdbc.driver.OracleDriver
        </property>
        <property name="show_sql">true</property>
        <property name="format_sql">true</property>
        <property name="hibernate.hbm2ddl.auto">update</property>
        <!--數(shù)據(jù)庫(kù)方言-->
        <property name="dialect">
            org.hibernate.dialect.OracleDialect
        </property>

        <!--映射類-->
        <mapping class="com.shuai.bean.User"/>

    </session-factory>
</hibernate-configuration>
項(xiàng)目目錄

4. 添加用戶信息到數(shù)據(jù)庫(kù)

addUser.jsp

可以用 form 表單

<h1>addUser</h1>

<form action="toSaveUser.action" method="post">
    用戶:<input type="text" name="user.name"><br>
    密碼:<input type="password" name="user.password"><br>
    <input type="submit" value="提交">
</form>

也可以用超鏈接

<h1>addUser</h1>

用戶: <input class="na" type="text" name="user.name"><br>
密碼: <input class="pwd" type="password" name="user.password"><br><br>
<a id="sb" class="btn btn-success" href="javascript:void(0);"
   style="width: 80px; margin-left: 70px">提交</a>
addUser

提交按鈕對(duì)應(yīng)的 href 是 index.js 中的跳轉(zhuǎn)到 toSaveUser.action 操作

$(function () {
    // id選擇器
    $("#sb").click(function () {
        console.log("in sb...");
        console.log($(".na").val() + " " + $(".pwd").val());

        // js對(duì)象
        var user = {};
        user['user.name'] = $(".na").val();
        user['user.password'] = $(".pwd").val();
        console.log(user);
        
        // 傳給 toSaveUser.action 頁(yè)面在前端輸入的 User
        $.post("toSaveUser.action", user, function () {
            console.log("發(fā)送成功");
        })
    });
});

UserAction 類中的 toSaveUser 函數(shù)對(duì)應(yīng) toSaveUser.action

//保存用戶
@Action(value = "/toSaveUser", results = {
        @Result(location = "/index.jsp"),
        @Result(name = ERROR, location = "/WEB-INF/jsp/addUser.jsp")
})
public String toSaveUser() {
    System.out.println("save user...");
    System.out.println("username: " + user.getName());
    System.out.println("password: " + user.getPassword());

    // $.post("toSaveUser.action", user,..) 接收 user
    try {
        service.registerUser(user); // 存入數(shù)據(jù)庫(kù)
        System.out.println("用戶存入數(shù)據(jù)庫(kù)...");
        return SUCCESS;
    } catch (ServiceException e) {
        e.printStackTrace();
        return ERROR;
    }
}

toSaveUser 函數(shù)調(diào)用 Service 接口的 registerUser 方法

UserServiceImpl (Service 的實(shí)現(xiàn)類)

package com.shuai.service;

import com.shuai.bean.User;
import com.shuai.common.ServiceException;
import com.shuai.dao.UserDao;

import java.util.List;

// UserService 的實(shí)現(xiàn)類
public class UserServiceImpl implements UserService {

    private UserDao dao = new UserDao();

    @Override
    public void registerUser(User user) throws ServiceException {
        User u = dao.findUserByName(user.getName());
        if (u != null) {
            throw new ServiceException("user exist!");
        } else {
            dao.saveUser(user); // 存入數(shù)據(jù)庫(kù)
        }
    }

    @Override
    public List<User> findAllUsers() throws ServiceException {
        return dao.findAllUsers();
    }
}

registerUser 函數(shù)調(diào)用 UserDao 的 findUserByName 和 saveUser 方法

package com.shuai.dao;

import com.shuai.bean.User;
import com.shuai.common.HibernateSessionFactory;
import org.hibernate.Criteria;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.criterion.Restrictions;

import java.util.List;

/**
 * Created by shuai
 * on 2017/8/21.
 */
public class UserDao {

    // 保存用戶
    public void saveUser(User user) {
        Session session = HibernateSessionFactory.getSession();
        Transaction ts = session.beginTransaction();
        session.save(user); // 事物內(nèi)容
        ts.commit();
    }

    // 查詢用戶
    public User findUserByName(String name) {

        Session session = HibernateSessionFactory.getSession();
        Criteria criteria = session.createCriteria(User.class);

        List<User> list = criteria.add(Restrictions.eq("name", name)).list();

        if (list.size() == 0) {
            return null;
        } else {
            return list.get(0); // 如果找到了枪向,第一個(gè)元素就是
        }
    }
}

這樣就可以把前端 addUser.jsp 中輸入的 User 存入數(shù)據(jù)庫(kù)勤揩。

5. 顯示用戶信息

操作順序 和 添加用戶信息 一樣

index.jsp 主頁(yè)面點(diǎn)進(jìn)超鏈接進(jìn)入 toShowUser.action

UserAction 類中 toShowUser.action

@Action(value = "/toShowUser", results = {
        @Result(location = "/WEB-INF/jsp/showUser.jsp"), // 可以這樣指定location路徑
        @Result(name = ERROR, location = "/index.jsp", type = "redirectAction")
})
public String toShowUser() throws ServiceException {

    System.out.println("show user...");

    List<User> list = service.findAllUsers();
    requestMap.put("list", list); // 通過(guò)UserAction類實(shí)現(xiàn)RequestAware接口傳值

    return SUCCESS;
}

UserServiceImpl (Service實(shí)現(xiàn)類)的 findAllUsers 方法

@Override
public List<User> findAllUsers() throws ServiceException {
    return dao.findAllUsers();
}

UserDao 類的 findAllUsers 方法

// 查詢所有用戶
public List<User> findAllUsers() {
    Session session = HibernateSessionFactory.getSession();
    SQLQuery sqlQuery = session.createSQLQuery("SELECT * FROM TBL_USER");
    sqlQuery.addEntity(User.class); // hibernate.cfg文件注冊(cè)了映射類
    return sqlQuery.list();
}

執(zhí)行數(shù)據(jù)庫(kù)查詢,返回 list

showUser.jsp 顯示表內(nèi)容

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>showUser</title>
    <link rel="stylesheet" >
</head>
<body>
<h1>showUser</h1>

<table class="table table-striped table-bordered" style="width: 50%">
    <thead>
    <tr>
        <th>username</th>
        <th>password</th>
    </tr>
    </thead>

    <tbody>
    <%--顯示傳入的list--%>
    <c:forEach items="${list}" var="v">
        <tr>
            <td> ${v.name}</td>
            <td> ${v.password}</td>
        </tr>
    </c:forEach>
    </tbody>
</table>

</body>
</html>
showUser
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末秘蛔,一起剝皮案震驚了整個(gè)濱河市陨亡,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌深员,老刑警劉巖负蠕,帶你破解...
    沈念sama閱讀 221,576評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異倦畅,居然都是意外死亡遮糖,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,515評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門叠赐,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)欲账,“玉大人,你說(shuō)我怎么就攤上這事芭概∪唬” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 168,017評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵谈山,是天一觀的道長(zhǎng)俄删。 經(jīng)常有香客問(wèn)我,道長(zhǎng)奏路,這世上最難降的妖魔是什么畴椰? 我笑而不...
    開(kāi)封第一講書人閱讀 59,626評(píng)論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮鸽粉,結(jié)果婚禮上斜脂,老公的妹妹穿的比我還像新娘。我一直安慰自己触机,他們只是感情好帚戳,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,625評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布玷或。 她就那樣靜靜地躺著,像睡著了一般片任。 火紅的嫁衣襯著肌膚如雪偏友。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書人閱讀 52,255評(píng)論 1 308
  • 那天对供,我揣著相機(jī)與錄音位他,去河邊找鬼。 笑死产场,一個(gè)胖子當(dāng)著我的面吹牛鹅髓,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播京景,決...
    沈念sama閱讀 40,825評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼窿冯,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了确徙?” 一聲冷哼從身側(cè)響起醒串,我...
    開(kāi)封第一講書人閱讀 39,729評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎鄙皇,沒(méi)想到半個(gè)月后厦凤,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,271評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡育苟,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,363評(píng)論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了椎木。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片违柏。...
    茶點(diǎn)故事閱讀 40,498評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖香椎,靈堂內(nèi)的尸體忽然破棺而出漱竖,到底是詐尸還是另有隱情,我是刑警寧澤畜伐,帶...
    沈念sama閱讀 36,183評(píng)論 5 350
  • 正文 年R本政府宣布馍惹,位于F島的核電站,受9級(jí)特大地震影響玛界,放射性物質(zhì)發(fā)生泄漏万矾。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,867評(píng)論 3 333
  • 文/蒙蒙 一慎框、第九天 我趴在偏房一處隱蔽的房頂上張望良狈。 院中可真熱鬧,春花似錦笨枯、人聲如沸薪丁。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 32,338評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)严嗜。三九已至粱檀,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間漫玄,已是汗流浹背茄蚯。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,458評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留称近,地道東北人第队。 一個(gè)月前我還...
    沈念sama閱讀 48,906評(píng)論 3 376
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像刨秆,于是被迫代替她去往敵國(guó)和親凳谦。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,507評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容

  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語(yǔ)法衡未,類相關(guān)的語(yǔ)法尸执,內(nèi)部類的語(yǔ)法,繼承相關(guān)的語(yǔ)法缓醋,異常的語(yǔ)法如失,線程的語(yǔ)...
    子非魚_t_閱讀 31,662評(píng)論 18 399
  • 一. Java基礎(chǔ)部分.................................................
    wy_sure閱讀 3,814評(píng)論 0 11
  • 概述 什么是Struts2的框架Struts2是Struts1的下一代產(chǎn)品,是在 struts1和WebWork的...
    inke閱讀 2,263評(píng)論 0 50
  • (一)Struts动雹、Spring槽卫、Hibernate、Mybatis框技術(shù) 1.Struts2.0有幾種標(biāo)簽庫(kù) 【...
    獨(dú)云閱讀 3,247評(píng)論 0 62
  • 丫頭難得從上阂闰穑回來(lái)休息兩天歼培,我和貨貨就逮著機(jī)會(huì)壹店,填鴨式的讓她吃遍家中的美食漾稀。這不女兒昨晚10.50到站,貨貨從晚飯...
    山青青閱讀 1,511評(píng)論 27 28