在前面的小节中,我们已经成功的将前台交给了yoman来处理。前后台的完全分离,意味着,我们可以在一台服务器上布署前台代码,然后在另一台服务器上布署后台代码。也就是说,即使我们将前台与后台布署在了同一台服务器上,实际上前台和后台也是两套不同的系统。不同的系统间通讯较同一系统间的通信显得复杂一些。
前台与后台大体是这样通讯的:
1. 前台 通过http协议,发送一个请求(GET\POST)。
2. 后台 接收到这个请求后,返回json数据。
3. 前台 接到json数据后,为用户做出响应。
由于浏览器与后台交互 ,本质上也是在进行get,post请求。所以javaee在接收数据时没有什么不同。那么不同点就在于:以前我们返回的html数据,而此时,我们需要返回json格式的数据。
下面,我们设置我们的后台,使其能够返回前台可用的JSON数据。
# 去除后台冗余的代码
我们在上一章中,在前台建立了性别过滤器,所以后台teacher实体中的getSexAttr()方法已经成为了冗余方法。实际在前后台分离的开发中,我们也的确不会在后台的实体中增加一些类似于getXXXXAttr()的方法来进行转换运算。当然,在本教程中,如果我们不删除getSexAttr()方法,还会引发一些json转换错误。
`getSexAttr()`方法位于
`package com.mengyunzhi.javaee.entity.teacher`中
# 引入JSON Plugin
struts如果返回json格式的数据呢?还记得我们一直强调的:
> 做为初学者的我们,我们的需求早早的就被大牛们解决了。
没错,struts返回json也是如此.
我们仍然打开,struts2.5的docs文档文件夹,并在此启用一个http-server服务,然后在本地来快速查看struts的文档。
> 我们可以使用:`http-server -p 端口号` 来自行指定一个端口来避免冲突。
![https://box.kancloud.cn/ce44b9c78141f512ae5896eb08b0b78b_1630x378.png](https://box.kancloud.cn/ce44b9c78141f512ae5896eb08b0b78b_1630x378.png)
我们依次打开:struts2-plugins/ -> struts2-json-plugin/ -> apidocs/
最终打开struts2-plugins官方文档: [http://127.0.0.1:8081/struts2-plugins/struts2-json-plugin/apidocs/](http://127.0.0.1:8081/struts2-plugins/struts2-json-plugin/apidocs/)
然后找到左侧菜单,找到:
![https://box.kancloud.cn/886d6dbfbf77daccf82d5642a20f23a1_684x830.png](https://box.kancloud.cn/886d6dbfbf77daccf82d5642a20f23a1_684x830.png)
有前期,我们有教程的情况下,其实我们并不需要把官方文档读一遍。
但读官方文档绝对是学习一门新语言最正确的途径。我们要尝试着去读官方的说明文档,在前期结合google的情况下,能够弄清楚怎么使用官方文档。官方文档中的一些示例代码又是该如何应用到具体项目中的。
## 复制jar包
我们在下载的struts中的lib文件夹中,找到struts2-json-plugin-2.3.31
![https://box.kancloud.cn/441ef1e1b3075e699b963157128c0b05_1620x670.png](https://box.kancloud.cn/441ef1e1b3075e699b963157128c0b05_1620x670.png)
并复制到javaee项目中的WebContent下的WEB-INF下的lib文件夹中。
## 添加Libraries
然后,我们在javaee上右键 -> build path -> Configure Build Path -> add JARS 然后找到我们刚刚复制过来的struts2-json-plugin-2.3.31, 应用并添加.
## 配置struts.xml
1. 修改包继承
```
...
<!-- 继承自json-default. json-default是json插件为我们提供的 -->
<package name="teacher" namespace="/teacher" extends="json-default">
...
```
2. 修改action返回类型及设置拦截器
```http://localhost:8080/javaee/teacher/
...
<!-- 列表 -->
<action name="index" class="com.mengyunzhi.javaee.action.teacher.Index">
<!-- 返回类型设置为json -->
<result name="success" type="json">
</result>
<!-- 配置拦截器,使传入的json数据能够成功的通过setXXX()方法来传值 -->
<interceptor-ref name="defaultStack" />
<interceptor-ref name="json">
<param name="enableSMD">true</param>
</interceptor-ref>
</action>
...
```
3. 重启tomcat
修改struts后,如果控制台没有重新启到tomcat的话,需要我们手动停止,然后再启动.
![https://box.kancloud.cn/72a945d05f7cdc07bdfa1bc42e99c40c_1882x190.png](https://box.kancloud.cn/72a945d05f7cdc07bdfa1bc42e99c40c_1882x190.png)
## 测试
此时,我们打开浏览器,并打开浏览器控制台。打开:[http://localhost:8080/javaee/teacher/](http://localhost:8080/javaee/teacher/)
查看返回信息:
![https://box.kancloud.cn/c3f5967672b6017b8b5c9c69876c7401_1020x344.png](https://box.kancloud.cn/c3f5967672b6017b8b5c9c69876c7401_1020x344.png)
返回值的类型为`application/json`,当浏览器接收到此信息时,会将接收到的数据做为json数据来处理。的确,当我们再查看JSON选项卡时,数据已经以json的形式展现给了我们。
我们再修改一下每页显示条数,然后查看数据返回是否正确。
[http://localhost:8080/javaee/teacher/?pageSize=3](http://localhost:8080/javaee/teacher/?pageSize=3)
![https://box.kancloud.cn/509326c302846a8f8bd0a8a6d7dbbd77_1678x402.png](https://box.kancloud.cn/509326c302846a8f8bd0a8a6d7dbbd77_1678x402.png)
数据返回3条数据,正确.
<hr />
### 删除后实体代码如下:
```
package com.mengyunzhi.javaee.entity;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.Index;
import com.mengyunzhi.javaee.common.db.MysqlJavaee;
// 声明主体
@Entity
public class Teacher {
// 声明主键
// 声明一个名为idGenerator的native类型构造器
// 使用这个构造器设置ID为自增属性
@Id
@GenericGenerator(name = "idGenerator", strategy = "native")
@GeneratedValue(generator = "idGenerator")
private int id; // 主键
private String name; // 姓名
// 声明长度(用户名不超过20位长度,定长能够提升效率)
@Column(columnDefinition = "char(20)")
// 声明为索引(该字段将来用于查询 ,增加索引将大幅提升查询效率)
@Index(name = "username")
private String username; // 用户名
private String email; // 邮箱
private Boolean sex = false; // 性别 0:男;1:女
// 密码采用sha1 md5加密,长度固定。
@Column(columnDefinition = "char(40)")
private String password; // 密码
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Boolean getSex() {
return sex;
}
public void setSex(Boolean sex) {
this.sex = sex;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Teacher() {
}
public Teacher(int id, String name, String username, String email,
Boolean sex, String password) {
// super();
this.id = id;
this.name = name;
this.username = username;
this.email = email;
this.sex = sex;
this.password = password;
}
public String toString() {
return "Teacher [id=" + id + ", name=" + name + ", username="
+ username + ", email=" + email + ", sex=" + sex
+ ", password=" + password + "]";
}
@SuppressWarnings("unchecked")
static public List<Teacher> all() {
// 实例化列表 teachers
List<Teacher> teachers = new ArrayList<Teacher>();
// 创建会话(这里的session也是会话的意思,我们以前接触的http中的session,处理的是用户与服务器的对话)
Session session = MysqlJavaee.getCurrentSession();
// 开启事务(使用缓冲池进行数据库的连接)
Transaction transaction = session.beginTransaction();
// 在这里,必须使用try catch finally语句。来确定会话正常关闭.
// 否则,当操作数据库产生错误时,你可能需要重启mysql服务
try {
// 查询Teacher表,注意:是Teacher ,而不是 teacher
Query query = session.createQuery("from Teacher");
// 预查询,只有在事务提交时,才进行查询操作
teachers = query.list();
// 提交事务
transaction.commit();
// 捕获异常
} catch (HibernateException e) {
// 如果事务执行异常,则回滚事务
if (null != transaction) {
transaction.rollback();
}
// 打印异常
e.printStackTrace();
} finally {
// 如果session处于开启状态,则关闭session
if (session.isOpen()) {
// 关闭会话
session.close();
}
}
return teachers;
}
/**
* 分页数据
*
* @param page
* 第几页
* @param pageSize
* 每页大小
* @return
*/
@SuppressWarnings("unchecked")
static public List<Teacher> paginate(int page, int pageSize) {
// 实例化列表 teachers
List<Teacher> teachers = new ArrayList<Teacher>();
// 创建会话(这里的session也是会话的意思,我们以前接触的http中的session,处理的是用户与服务器的对话)
Session session = MysqlJavaee.getCurrentSession();
// 开启事务(使用缓冲池进行数据库的连接)
Transaction transaction = session.beginTransaction();
// 在这里,必须使用try catch finally语句。来确定会话正常关闭.
// 否则,当操作数据库产生错误时,你可能需要重启mysql服务
try {
// 查询Teacher表,注意:是Teacher ,而不是 teacher
Query query = session.createQuery("from Teacher");
// 计算并设置第一条记录的位置
int index = (page - 1) * pageSize;
query.setFirstResult(index);
// 每页大小
query.setMaxResults(pageSize);
teachers = query.list();
// 提交事务
transaction.commit();
// 捕获异常
} catch (HibernateException e) {
// 如果事务执行异常,则回滚事务
if (null != transaction) {
transaction.rollback();
}
// 打印异常
e.printStackTrace();
} finally {
// 如果session处于开启状态,则关闭session
if (session.isOpen()) {
// 关闭会话
session.close();
}
}
return teachers;
}
/**
* 分页数据
*
* @param page
* 第几页
* @param pageSize
* 每页大小
* @return
*/
@SuppressWarnings("unchecked")
static public List<Teacher> paginate(String name, int page, int pageSize) {
// 实例化列表 teachers
List<Teacher> teachers = new ArrayList<Teacher>();
// 创建会话(这里的session也是会话的意思,我们以前接触的http中的session,处理的是用户与服务器的对话)
Session session = MysqlJavaee.getCurrentSession();
// 开启事务(使用缓冲池进行数据库的连接)
Transaction transaction = session.beginTransaction();
// 在这里,必须使用try catch finally语句。来确定会话正常关闭.
// 否则,当操作数据库产生错误时,你可能需要重启mysql服务
try {
// 查询Teacher表,注意:是Teacher ,而不是 teacher
Query query = session.createQuery("from Teacher where name like '%"
+ name + "%'");
// 计算并设置第一条记录的位置
int index = (page - 1) * pageSize;
query.setFirstResult(index);
// 每页大小
query.setMaxResults(pageSize);
teachers = query.list();
// 提交事务
transaction.commit();
// 捕获异常
} catch (HibernateException e) {
// 如果事务执行异常,则回滚事务
if (null != transaction) {
transaction.rollback();
}
// 打印异常
e.printStackTrace();
} finally {
// 如果session处于开启状态,则关闭session
if (session.isOpen()) {
// 关闭会话
session.close();
}
}
return teachers;
}
/**
* 通过ID获取Teacher实体
*
* @param id
* @return
*/
static public Teacher getTeacherById(int id) {
// 实例化Teacher
Teacher teacher = new Teacher();
// 创建会话(这里的session也是会话的意思,我们以前接触的http中的session,处理的是用户与服务器的对话)
Session session = MysqlJavaee.getCurrentSession();
// 开启事务(使用缓冲池进行数据库的连接)
Transaction transaction = session.beginTransaction();
// 在这里,必须使用try catch finally语句。来确定会话正常关闭.
// 否则,当操作数据库产生错误时,你可能需要重启mysql服务
try {
// 使用Teacher.class来获取到Teacher的类名(包括包名)
teacher = (Teacher) session.get(Teacher.class, id);
// 提交事务
transaction.commit();
// 捕获异常
} catch (HibernateException e) {
// 如果事务执行异常,则回滚事务
if (null != transaction) {
transaction.rollback();
}
// 打印异常
e.printStackTrace();
} finally {
// 如果session处于开启状态,则关闭session
if (session.isOpen()) {
// 关闭会话
session.close();
}
}
return teacher;
}
public Boolean update() {
// 创建会话(这里的session也是会话的意思,我们以前接触的http中的session,处理的是用户与服务器的对话)
Session session = MysqlJavaee.getCurrentSession();
// 开启事务(使用缓冲池进行数据库的连接)
Transaction transaction = session.beginTransaction();
// 在这里,必须使用try catch finally语句。来确定会话正常关闭.
// 否则,当操作数据库产生错误时,你可能需要重启mysql服务
try {
// 更新
session.update(this);
// 提交事务
transaction.commit();
// 捕获异常
} catch (HibernateException e) {
// 如果事务执行异常,则回滚事务
if (null != transaction) {
transaction.rollback();
}
// 打印异常
e.printStackTrace();
} finally {
// 如果session处于开启状态,则关闭session
if (session.isOpen()) {
// 关闭会话
session.close();
}
}
return true;
}
public Boolean delete() {
// 创建会话(这里的session也是会话的意思,我们以前接触的http中的session,处理的是用户与服务器的对话)
Session session = MysqlJavaee.getCurrentSession();
// 开启事务(使用缓冲池进行数据库的连接)
Transaction transaction = session.beginTransaction();
// 在这里,必须使用try catch finally语句。来确定会话正常关闭.
// 否则,当操作数据库产生错误时,你可能需要重启mysql服务
try {
// 删除
session.delete(this);
// 提交事务
transaction.commit();
// 捕获异常
} catch (HibernateException e) {
// 如果事务执行异常,则回滚事务
if (null != transaction) {
transaction.rollback();
}
// 打印异常
e.printStackTrace();
} finally {
// 如果session处于开启状态,则关闭session
if (session.isOpen()) {
// 关闭会话
session.close();
}
}
return true;
}
}
```
当习惯了完美的前端自动化开发后,我们好像已经不愿意在去手工去写那么冗余的代码了。
- README
- 第一章:准备
- 第二章:Hello World!
- 第一节:查看工程文件
- 第二节:JDK、JRE与环境变量
- 第三节:index.jsp
- 第三章:Hello Struts
- 第一节:Web.xml
- 第二节:单入口
- 第三节:Hello Struts
- 第四节:触发C层
- 第四章:建立数据表
- 第一节:建立实体类
- 第二节:测试一
- 第三节:测试二
- 第四节:引入Hibernate
- 第五节:配置Hibernate
- 第六节:建立连接
- 第七节:实体类映射数据表
- 第八节:完善数据表
- 第五章:教师管理
- 第一节:增加数据--add
- 第二节:增加数据--save
- 1 获取传入数据数据
- 2 数据写入测试
- 3 对接C层
- 第三节:数据列表
- 1 获取数据
- 2 重构代码
- 3 C层对接--初始化
- 4 C层添加数据
- 5 V层显示数据
- 6 获取数据库中数据
- 7 显示性别
- 8 分页
- 9 条件查询
- 第四节:修改数据
- 1 edit
- 2 update
- 第五节:删除数据
- 第六节:总结
- 第六章:重构C层
- 第一节:继承ActionSupport类
- 第二节:数据验证
- 第七章:前台分离(前台)
- 第一节:环境搭建
- 第二节:运行环境
- 第三节:共享开发环境
- 第四节:生产环境
- 第八章:前台开发(前台)
- 第一节:本地化
- 第二节:教师列表
- 1 引入M层
- 2 模拟后台返回数据
- 3 C与M对接
- 4 C与V对接
- 第九章:前后台对接(前后台)
- 第一节:后台输出json(后台)
- 第二节:对接前台(全栈)
- 第二节:对接API(前台)
- 第二节:跨域请求(后台)
- 第三节:重构代码(前台)
- 第十章:重构后台M层
- 第一节:数据访问DAO层
- 第二节:项目整体重构
- 第十一章:用户登陆(前后台)
- 第一节:制定规范
- 第二节:定制测试用例
- 第三节:后台输入测试代码(后台)
- 第四节:postman(后台)
- 第五节:新建用户登陆模块(前台)
- 第六节:代码重构(前台)
- 第十二章:班级管理(前后台)
- 第一节:班级列表
- 1 原型开发
- 2 制定规范
- 3 后台对接开发
- 4 前台对接开发
- 第二节:Add
- 1 原型开发
- 2 制定规范
- 3 后台对接开发
- 4 前台对接开发
- 第三节:Save
- 1 制定规范
- 2 后台对接开发
- 3 前台对接开发
- 第四节:Edit
- 1 原型开发
- 2 制定规范
- 3 后台对接开发
- 4 前台对接开发
- 第五节:Update
- 1 制定规范
- 2 后台对接开发
- 3 前台对接开发
- 第六节:Delete
- 1 制定规范
- 2 后台对接开发
- 3 前台对接开发
- 第七节:小结
- 第十三章:班级管理(API)
- 第一节:ER图
- 第二节:create
- 1 实体层
- 2 dao层
- 3 service(server)层
- 4 action层
- 第三节:ManyToOne
- 第四节:Read
- 1 service(server)层
- 2 action层
- 第五节:update
- 1 service(server)层
- 2 action层
- 第六节:update
- 第十四章:重构服务层