闲来无事,看了看别人的博客文档也跟着敲了敲,特地记录下来,方便以后学习:
spring版本:4.0.6
mybatis版本:3.2.5
所有jar包打包下载:http://pan.baidu.com/s/1qLEaU
1、项目目录结构
其中,controller包下存放控制层文件,dao下存放各个model类相关的数据库操作接口,entity下放置各种model类,mappers下放置各个dao对应的映射文件,service服务层就不说了,放置各种service接口,impl是其具体实现类。
2、web.xml文件配置
<?xml version="1.0" encoding="UTF-8"?> <web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"> <display-name></display-name> <welcome-file-list> <welcome-file>login.jsp</welcome-file> </welcome-file-list> <!-- Spring配置文件 --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext.xml</param-value> </context-param> <!-- 编码过滤器 --> <filter> <filter-name>encodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <async-supported>true</async-supported> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> </filter> <filter-mapping> <filter-name>encodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- 配置Spring监听器 --> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!-- 添加对SpringMVC的支持 --> <servlet> <servlet-name>SpringMVC</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring-mvc.xml</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>SpringMVC</servlet-name> <url-pattern>*.do</url-pattern> </servlet-mapping> </web-app>
3、log4j.properties配置日志
log4j.rootLogger=DEBUG, Console #Console log4j.appender.Console=org.apache.log4j.ConsoleAppender log4j.appender.Console.layout=org.apache.log4j.PatternLayout log4j.appender.Console.layout.ConversionPattern=%d [%t] %-5p [%c] - %m%n log4j.logger.java.sql.ResultSet=INFO log4j.logger.org.apache=INFO log4j.logger.java.sql.Connection=DEBUG log4j.logger.java.sql.Statement=DEBUG log4j.logger.java.sql.PreparedStatement=DEBUG
4、mybatis-config.xml配置
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <!-- 别名 --> <typeAliases> <package name="com.java.entity" /> <!-- 后面书写类全名时默认加该包名前缀如:<resultMap type="User"... --> </typeAliases> </configuration>
5、spring-mvc.xml配置
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation=" http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd"> <!-- 使用注解的包,包括子集 --> <context:component-scan base-package="com.java.controller"></context:component-scan> <!-- 视图解析器 --> <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/"></property> <property name="suffix" value=".jsp"></property> </bean> </beans>
6、applicationContext.xml配置
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation=" http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd"> <!-- 自动扫描该包下面的bean文件 --> <context:component-scan base-package="com.java.service"></context:component-scan> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <!-- <property name="driverClassName" value="com.microsoft.sqlserver.jdbc.SQLServerDriver"/> --> <property name="driverClassName" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/crm"/> <property name="username" value="root"/> <property name="password" value="root"/> </bean> <!-- 配置MyBatis的sqlSessionFactory --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource"></property> <property name="configLocation" value="classpath:mybatis-config.xml"></property> <property name="mapperLocations" value="classpath:com/java/mappers/*.xml"></property> </bean> <!-- Mapper接口所在包名,Spring会自动查找其下的Mapper --> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.java.dao"></property> <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property> </bean> <!-- 配置transactionManager事务管理器 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean> <!-- 配置事物通知属性 --> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <!-- 定义事物传播特性 --> <tx:attributes> <tx:method name="insert" propagation="REQUIRED"/> <tx:method name="update*" propagation="REQUIRED" /> <tx:method name="edit*" propagation="REQUIRED" /> <tx:method name="save*" propagation="REQUIRED" /> <tx:method name="add*" propagation="REQUIRED" /> <tx:method name="new*" propagation="REQUIRED" /> <tx:method name="set*" propagation="REQUIRED" /> <tx:method name="remove*" propagation="REQUIRED" /> <tx:method name="delete*" propagation="REQUIRED" /> <tx:method name="change*" propagation="REQUIRED" /> <tx:method name="check*" propagation="REQUIRED" /> <tx:method name="get*" propagation="REQUIRED" read-only="true" /> <tx:method name="find*" propagation="REQUIRED" read-only="true" /> <tx:method name="load*" propagation="REQUIRED" read-only="true" /> <tx:method name="*" propagation="REQUIRED" read-only="true" /> </tx:attributes> </tx:advice> <!-- 配置事物切面 --> <aop:config> <aop:pointcut expression="execution(* com.java.service.*.*(..))" id="serviceOperation"/> <aop:advisor advice-ref="txAdvice" pointcut-ref="serviceOperation"/> </aop:config> </beans>
7、增删改查具体实现
主界面很简单:
详细html实现:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <% String path = request.getContextPath(); String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path + "/"; %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <base href="<%=basePath%>"> <title>My JSP 'userManage.jsp' starting page</title> <link rel="stylesheet" type="text/css" href="${pageContext.request.contextPath}/jquery-easyui-1.3.3/themes/default/easyui.css"> <link rel="stylesheet" type="text/css" href="${pageContext.request.contextPath}/jquery-easyui-1.3.3/themes/icon.css"> <script type="text/javascript" src="${pageContext.request.contextPath}/jquery-easyui-1.3.3/jquery.min.js"></script> <script type="text/javascript" src="${pageContext.request.contextPath}/jquery-easyui-1.3.3/jquery.easyui.min.js"></script> <script type="text/javascript" src="${pageContext.request.contextPath}/jquery-easyui-1.3.3/locale/easyui-lang-zh_CN.js"></script> <script type="text/javascript"> var url; function searchUser() { $("#dg").datagrid('load', { "userName" : $("#s_userName").val() }); } function openUserAddDialog() { $("#dlg").dialog("open").dialog("setTitle", "添加用户信息"); url = "${pageContext.request.contextPath}/user/save.do"; } function openUserModifyDialog() { var selectedRows = $("#dg").datagrid("getSelections"); if (selectedRows.length != 1) { $.messager.alert("系统提示", "请选择一条要编辑的数据!"); return; } var row = selectedRows[0]; $("#dlg").dialog("open").dialog("setTitle", "编辑用户信息"); $("#fm").form("load", row); url = "${pageContext.request.contextPath}/user/save.do?id=" + row.id; } function saveUser() { $("#fm").form("submit", { url : url, onSubmit : function() { if ($("#roleName").combobox("getValue") == "") { $.messager.alert("系统提示", "请选择用户角色!"); return false; } return $(this).form("validate"); }, success : function(result) { var result = eval('(' + result + ')'); if (result.success) { $.messager.alert("系统提示", "保存成功!"); resetValue(); $("#dlg").dialog("close"); $("#dg").datagrid("reload"); } else { $.messager.alert("系统提示", "保存失败!"); return; } } }); } function resetValue() { $("#userName").val(""); $("#password").val(""); $("#trueName").val(""); $("#email").val(""); $("#phone").val(""); $("#roleName").combobox("setValue", ""); } function closeUserDialog() { $("#dlg").dialog("close"); resetValue(); } function deleteUser() { var selectedRows = $("#dg").datagrid("getSelections"); if (selectedRows.length == 0) { $.messager.alert("系统提示", "请选择要删除的数据!"); return; } var strIds = []; for ( var i = 0; i < selectedRows.length; i++) { strIds.push(selectedRows[i].id); } var ids = strIds.join(","); $.messager.confirm("系统提示", "您确定要删除这<font color=red>" + selectedRows.length + "</font>条数据吗?", function(r) { if (r) { $.post("${pageContext.request.contextPath}/user/delete.do", { ids : ids }, function(result) { if (result.success) { $.messager.alert("系统提示", "数据已成功删除!"); $("#dg").datagrid("reload"); } else { $.messager.alert("系统提示", "数据删除失败,请联系系统管理员!"); } }, "json"); } }); } </script> </head> <body style="margin: 1px"> <table id="dg" title="用户管理" class="easyui-datagrid" fitColumns="true" pagination="true" rownumbers="true" url="${pageContext.request.contextPath}/user/list.do" fit="true" toolbar="#tb"> <thead> <tr> <th field="cb" checkbox="true" align="center"></th> <th field="id" width="50" align="center">编号</th> <th field="userName" width="50" align="center">用户名</th> <th field="password" width="50" align="center">密码</th> <th field="trueName" width="50" align="center">真实姓名</th> <th field="email" width="50" align="center">邮件</th> <th field="phone" width="50" align="center">联系电话</th> <th field="roleName" width="50" align="center">角色</th> </tr> </thead> </table> <div id="tb"> <a href="javascript:openUserAddDialog()" class="easyui-linkbutton" iconCls="icon-add" plain="true">添加</a> <a href="javascript:openUserModifyDialog()" class="easyui-linkbutton" iconCls="icon-edit" plain="true">修改</a> <a href="javascript:deleteUser()" class="easyui-linkbutton" iconCls="icon-remove" plain="true">删除</a> <div> 用户名: <input type="text" id="s_userName" size="20" οnkeydοwn="if(event.keyCode == 13)searchUser()" /> <a href="javascript:searchUser()" class="easyui-linkbutton" iconCls="icon-search" plain="true">查询</a> </div> <div id="dlg-buttons"> <a href="javascript:saveUser()" class="easyui-linkbutton" iconCls="icon-ok">保存</a> <a href="javascript:closeUserDialog()" class="easyui-linkbutton" iconCls="icon-cancel">关闭</a> </div> <div id="dlg" class="easyui-dialog" style="width: 730px;height:280px;padding:10px 10px;" closed="true" buttons="#dlg-buttons"> <form method="post" id="fm"> <table cellspacing="8px;"> <tr> <td>用户名:</td> <td><input type="text" id="userName" name="userName" class="easyui-validatebox" required="true" /> <span style="color: red">*</span> </td> <td> </td> <td>密码:</td> <td><input type="password" id="password" name="password" class="easyui-validatebox" required="true" /> <span style="color: red">*</span> </td> </tr> <tr> <td>真实姓名:</td> <td><input type="text" id="trueName" name="trueName" class="easyui-validatebox" required="true" /> <span style="color: red">*</span> </td> <td> </td> <td>邮箱:</td> <td><input type="text" id="email" name="email" validType="email" class="easyui-validatebox" required="true" /> <span style="color: red">*</span> </td> </tr> <tr> <td>联系电话:</td> <td><input type="text" id="phone" name="phone" class="easyui-validatebox" required="true" /> <span style="color: red">*</span> </td> <td> </td> <td>用户角色:</td> <td><select name="roleName" class="easyui-combobox" id="roleName" style="width: 154px;" editable="false" panelHeight="auto"> <option value="">请选择角色</option> <option value="系统管理员">系统管理员</option> <option value="销售主管">销售主管</option> <option value="客户经理">客户经理</option> <option value="高管">高管</option> </select> <span style="color: red">*</span> </td> </tr> </table> </form> </div> </body> </html>
再来看看目录结构:
UserController:
package com.java.controller; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import net.sf.json.JSONArray; import net.sf.json.JSONObject; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import com.java.entity.PageBean; import com.java.entity.User; import com.java.service.UserService; import com.java.util.ResponseUtil; import com.java.util.StringUtil; import com.sun.mail.iap.Response; /** * 用户Controller层 * @author Administrator * */ @Controller @RequestMapping("/user") public class UserController { @Resource private UserService userService; /** * 删除用户 * @param ids * @param res * @return * @throws Exception */ @RequestMapping("/delete") public String delete(@RequestParam(value="ids") String ids,HttpServletResponse res) throws Exception{ String[] idStr = ids.split(","); JSONObject jsonObject = new JSONObject(); for (String id : idStr) { userService.delete(Integer.parseInt(id)); } jsonObject.put("success", true); ResponseUtil.write(res, jsonObject); return null; } /** * 添加或者修改 * @param user * @param res * @return * @throws Exception */ @RequestMapping("/save") public String save(User user,HttpServletResponse res) throws Exception{ //操作记录条数,初始化为0 int resultTotal = 0; if (user.getId() == null) { resultTotal = userService.add(user); }else{ resultTotal = userService.update(user); } JSONObject jsonObject = new JSONObject(); if(resultTotal > 0){ //说明修改或添加成功 jsonObject.put("success", true); }else{ jsonObject.put("success", false); } ResponseUtil.write(res, jsonObject); return null; } /** * 用户登录 * @param user * @param request * @return * @throws Exception */ @RequestMapping("/login") public String login(User user, HttpServletRequest request) throws Exception{ User resultUser = userService.login(user); if (resultUser == null) { request.setAttribute("user", resultUser); request.setAttribute("errorMsg", "用户名或密码错误"); return "login"; }else { HttpSession session = request.getSession(); session.setAttribute("currentUser", resultUser); return "redirect:/main.jsp"; } } /** * 用户分页查询 * @param page * @param rows * @param s_user * @param res * @return * @throws Exception */ @RequestMapping("/list") public String list(@RequestParam(value="page",required=false) String page,@RequestParam(value="rows",required=false) String rows,User s_user,HttpServletResponse res) throws Exception{ PageBean pageBean=new PageBean(Integer.parseInt(page),Integer.parseInt(rows)); Map<String,Object> map=new HashMap<String,Object>(); map.put("userName", StringUtil.formatLike(s_user.getUserName())); map.put("start", pageBean.getStart()); map.put("size", pageBean.getPageSize()); List<User> userList=userService.find(map); Long total=userService.getTotal(map); JSONObject result=new JSONObject(); JSONArray jsonArray=JSONArray.fromObject(userList); result.put("rows", jsonArray); result.put("total", total); ResponseUtil.write(res, result); return null; } }
UserDao:
package com.java.dao; import java.util.List; import java.util.Map; import com.java.entity.User; /** * 用户DAO接口 * * @author Administrator * */ public interface UserDao { /** * 用户登录 * @param user * @return */ public User login(User user); /** * 用户查询 * @param map * @return用户集合 */ public List<User> find(Map<String, Object> map); /** * 获取总记录数 * @param map * @return获取的total数 */ public Long getTotal(Map<String, Object> map); /** * 修改用户 * @param user * @return影响的记录数 */ public int update(User user); /** * 添加用户 * @param user * @return影响的记录数 */ public int add(User user); /** * 删除用户 * @param id * @return */ public int delete(Integer id); }
PageBean,用来分页的一个工具类:
package com.java.entity; /** * 分页Model类 * @author * */ public class PageBean { private int page; // 第几页 private int pageSize; // 每页记录数 private int start; // 起始页 public PageBean(int page, int pageSize) { super(); this.page = page; this.pageSize = pageSize; } public int getPage() { return page; } public void setPage(int page) { this.page = page; } public int getPageSize() { return pageSize; } public void setPageSize(int pageSize) { this.pageSize = pageSize; } public int getStart() { return (page-1)*pageSize; } }
User,用户实体类:
package com.java.entity; /** * 用户实体 * @author Administrator * */ public class User { private Integer id; private String userName; private String password; private String trueName; private String email; private String phone; private String roleName; //角色名称:系统管理员、销售主管、客户经理、高管 public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getTrueName() { return trueName; } public void setTrueName(String trueName) { this.trueName = trueName; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public String getPhone() { return phone; } public void setPhone(String phone) { this.phone = phone; } public String getRoleName() { return roleName; } public void setRoleName(String roleName) { this.roleName = roleName; } }
UserService:
package com.java.service; import java.util.List; import java.util.Map; import com.java.entity.User; /** * UserService接口 * @author Administrator * */ public interface UserService { /** * 用户登录 * @param user * @return */ public User login(User user); /** * 用户查询 * @param map * @return */ public List<User> find(Map<String, Object> map); /** * 获取总记录数 * @param map * @return */ public Long getTotal(Map<String, Object> map); /** * 修改用户 * @param user * @return影响的记录数 */ public int update(User user); /** * 添加用户 * @param user * @return影响的记录数 */ public int add(User user); /** * 删除用户 * @param id * @return */ public int delete(Integer id); }
UserServiceImpl:
package com.java.service.impl; import java.util.List; import java.util.Map; import javax.annotation.Resource; import org.springframework.stereotype.Service; import com.java.dao.UserDao; import com.java.entity.User; import com.java.service.UserService; /** * UserService实现类 * @author Administrator * */ @Service("userService") public class UserServiceImpl implements UserService{ @Resource private UserDao userDao; @Override public User login(User user) { return userDao.login(user); } @Override public List<User> find(Map<String, Object> map) { return userDao.find(map); } @Override public Long getTotal(Map<String, Object> map) { return userDao.getTotal(map); } @Override public int update(User user) { return userDao.update(user); } @Override public int add(User user) { return userDao.add(user); } @Override public int delete(Integer id) { return userDao.delete(id); } }
ResponseUtil工具类,主要用于返回json数据:
package com.java.util; import java.io.PrintWriter; import javax.servlet.http.HttpServletResponse; public class ResponseUtil { public static void write(HttpServletResponse response,Object object)throws Exception{ response.setContentType("text/html;charset=utf-8"); PrintWriter out=response.getWriter(); out.println(object); out.flush(); out.close(); } }
StringUtil,字符串工具类:
package com.java.util; /** * 字符串工具类 * @author * */ public class StringUtil { /** * 判断是否是空 * @param str * @return */ public static boolean isEmpty(String str){ if(str==null||"".equals(str.trim())){ return true; }else{ return false; } } /** * 判断是否不是空 * @param str * @return */ public static boolean isNotEmpty(String str){ if((str!=null)&&!"".equals(str.trim())){ return true; }else{ return false; } } /** * 格式化模糊查询 * @param str * @return */ public static String formatLike(String str){ if(isNotEmpty(str)){ return "%"+str+"%"; }else{ return null; } } }
UserMapper.xml,mybatis所谓的动态sql语句,全部封装在这里:
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.java.dao.UserDao"> <!-- 先定义一个Interface,UserMapper,然后Mapper文件的namespace指向的就是这个Interface, UserInterface里定义的方法和UserMapper.xml文件中的一样, 然后代码里直接使用接口 --> <resultMap type="User" id="UserResult"> <result property="id" column="id" /> <result property="userName" column="userName" /> <result property="password" column="password" /> <result property="trueName" column="trueName" /> <result property="email" column="email" /> <result property="phone" column="phone" /> <result property="roleName" column="roleName" /> </resultMap> <!-- 所谓的动态SQL语句 --> <select id="login" parameterType="User" resultMap="UserResult"> select * from userInfo where userName = #{userName} and password = #{password} and roleName = #{roleName} </select> <!-- 用户查询 --> <select id="find" parameterType="Map" resultMap="UserResult"> select * from userInfo <where> <if test="userName!=null and userName!='' "> and userName like #{userName} </if> </where> <if test="start!=null and size!=null"> limit #{start},#{size} </if> </select> <select id="getTotal" parameterType="Map" resultType="Long"> select count(*) from userInfo <where> <if test="userName!=null and userName!='' "> and userName like #{userName} </if> </where> </select> <!-- 用户添加 --> <insert id="add" parameterType="User"> insert into userInfo values(null,#{userName},#{password},#{trueName},#{email},#{phone},#{roleName}) </insert> <!-- 用户修改 --> <update id="update" parameterType="User"> update userInfo <set> <if test="userName != null and userName != ''">userName = #{userName},</if> <if test="password != null and password != ''">password = #{password},</if> <if test="trueName != null and trueName != ''">trueName = #{trueName},</if> <if test="email != null and email != ''">email = #{email},</if> <if test="phone != null and phone != ''">phone = #{phone},</if> <if test="roleName != null and roleName != ''">roleName = #{roleName},</if> </set> where id = #{id} </update> <!-- 用户删除 --> <delete id="delete" parameterType="Integer"> delete from userInfo where id = #{id} </delete> </mapper>
最后是数据表结构:
相比hibernate,mybatis轻量级很多,但是新手最容易也最难搞定的往往是环境搭建部分,一不留神就是各种jar包冲突,真叫人抓狂啊啊,以后还得留意呵。