You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在本地servlet中使用Google App Engine的Objectify实现数据增删改

GAE Servlet + JSON场景Objectify实现学生数据CRUD示例

前置配置

1. 引入依赖

在pom.xml中添加相关依赖:

<!-- Objectify 依赖 -->
<dependency>
    <groupId>com.googlecode.objectify</groupId>
    <artifactId>objectify</artifactId>
    <version>6.1.1</version>
</dependency>
<!-- Servlet API 依赖 -->
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>4.0.1</version>
    <scope>provided</scope>
</dependency>
<!-- Jackson JSON 处理依赖 -->
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.15.2</version>
</dependency>

2. 配置web.xml

添加Objectify过滤器保证请求会话正常,同时配置初始化监听器注册实体:

<!-- Objectify 过滤器 -->
<filter>
    <filter-name>ObjectifyFilter</filter-name>
    <filter-class>com.googlecode.objectify.ObjectifyFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>ObjectifyFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

<!-- 实体注册监听器 -->
<listener>
    <listener-class>com.example.ObjectifyInitListener</listener-class>
</listener>

<!-- Servlet 配置 -->
<servlet>
    <servlet-name>StudentServlet</servlet-name>
    <servlet-class>com.example.StudentServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>StudentServlet</servlet-name>
    <url-pattern>/Servlet</url-pattern>
</servlet-mapping>

3. 编写实体类和初始化监听器

Student实体类(替换原有Database类)

package com.example;

import com.googlecode.objectify.annotation.Entity;
import com.googlecode.objectify.annotation.Id;

@Entity
public class Student {
    @Id
    private Long id;
    private String first_name;
    private String last_name;
    private String fullname;
    private String email;
    private String address;
    private String contact;

    // 必须保留无参构造函数
    public Student() {}

    // 所有字段的getter和setter
    public Long getId() {return id;}
    public void setId(Long id) {this.id = id;}
    public String getFirst_name() {return first_name;}
    public void setFirst_name(String first_name) {this.first_name = first_name;}
    public String getLast_name() {return last_name;}
    public void setLast_name(String last_name) {this.last_name = last_name;}
    public String getFullname() {return fullname;}
    public void setFullname(String fullname) {this.fullname = fullname;}
    public String getEmail() {return email;}
    public void setEmail(String email) {this.email = email;}
    public String getAddress() {return address;}
    public void setAddress(String address) {this.address = address;}
    public String getContact() {return contact;}
    public void setContact(String contact) {this.contact = contact;}
}

Objectify初始化监听器

package com.example;

import com.googlecode.objectify.ObjectifyService;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

public class ObjectifyInitListener implements ServletContextListener {
    @Override
    public void contextInitialized(ServletContextEvent sce) {
        // 注册实体类,必须在所有Objectify操作前执行
        ObjectifyService.register(Student.class);
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {}
}

重构后的Servlet代码

package com.example;

import com.fasterxml.jackson.databind.ObjectMapper;
import static com.googlecode.objectify.ObjectifyService.ofy;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.List;

public class StudentServlet extends HttpServlet {
    private ObjectMapper mapper = new ObjectMapper();

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("application/json");
        response.setCharacterEncoding("UTF-8");
        String action = request.getParameter("action");

        // 查询所有学生数据
        if ("list".equals(action)) {
            List<Student> students = ofy().load().type(Student.class).list();
            mapper.writeValue(response.getOutputStream(), students);
            return;
        }

        // 读取请求体JSON
        BufferedReader br = new BufferedReader(new InputStreamReader(request.getInputStream()));
        StringBuilder jsonBuilder = new StringBuilder();
        String line;
        while ((line = br.readLine()) != null) {
            jsonBuilder.append(line);
        }
        String json = jsonBuilder.toString();

        // 新增学生
        if ("add".equals(action)) {
            Student student = mapper.readValue(json, Student.class);
            ofy().save().entity(student).now();
        }
        // 编辑学生
        else if ("edit".equals(action)) {
            Student updateStudent = mapper.readValue(json, Student.class);
            Student existStudent = ofy().load().type(Student.class).id(updateStudent.getId()).now();
            if (existStudent != null) {
                existStudent.setFirst_name(updateStudent.getFirst_name());
                existStudent.setLast_name(updateStudent.getLast_name());
                existStudent.setFullname(updateStudent.getFullname());
                existStudent.setEmail(updateStudent.getEmail());
                existStudent.setAddress(updateStudent.getAddress());
                existStudent.setContact(updateStudent.getContact());
                ofy().save().entity(existStudent).now();
            }
        }
        // 删除学生
        else if ("delete".equals(action)) {
            Student deleteStudent = mapper.readValue(json, Student.class);
            ofy().delete().type(Student.class).id(deleteStudent.getId()).now();
        }

        // 返回最新的学生列表
        List<Student> students = ofy().load().type(Student.class).list();
        mapper.writeValue(response.getOutputStream(), students);
    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }
}

调整后的myFunction.js代码

// 全局变量保存当前编辑的学生ID
let editId = null;

// 页面加载完成后绑定事件
$(document).ready(function () {
    // 页面加载时先拉取所有学生数据
    loadStudentList();

    // 注册/更新按钮点击事件
    $("#bttHello").click(function () {
        let studentData = {};
        studentData.id = editId;
        studentData.fullname = $("#fullname").val();
        studentData.first_name = $('#first_name').val();
        studentData.last_name = $('#last_name').val();
        studentData.email = $('#email').val();
        studentData.address = $('#address').val();
        studentData.contact = $('#contact').val();

        let action = editId ? 'edit' : 'add';
        $.ajax({
            url: 'Servlet?action=' + action,
            type: 'POST',
            dataType: 'json',
            data: JSON.stringify(studentData),
            contentType: 'application/json',
            success: function (result) {
                renderStudentTable(result);
                // 清空表单
                $('#first_name, #last_name, #fullname, #email, #address, #contact').val('');
                editId = null;
                $("#bttHello").val('Register');
            },
            error: function (data, status, er) {
                alert("操作失败: " + er);
            }
        });
    });
});

// 加载学生列表
function loadStudentList() {
    $.ajax({
        url: 'Servlet?action=list',
        type: 'GET',
        dataType: 'json',
        success: function (result) {
            renderStudentTable(result);
        }
    });
}

// 渲染学生表格
function renderStudentTable(students) {
    $("tr:has(td)").remove();
    $.each(students, function (index, student) {
        $("#added-data").append($('<tr/>')
            .append($('<td/>').html(student.first_name))
            .append($('<td/>').html(student.last_name))
            .append($('<td/>').html(student.fullname))
            .append($('<td/>').html(student.email))
            .append($('<td/>').html(student.address))
            .append($('<td/>').html(student.contact))
            .append($('<td/>').html("<button type='button' class='btn btn-default btn-sm edit-btn' data-id='" + student.id + "'>" + "<span class= 'glyphicon glyphicon-pencil' ></span> 编辑</button>"))
            .append($('<td/>').html("<button type='button' class='btn btn-default btn-sm delete-btn' data-id='" + student.id + "'>" + "<span class='glyphicon glyphicon-remove'></span> 删除</button>"))
        );
    });

    // 绑定编辑按钮事件
    $(".edit-btn").click(function () {
        editId = $(this).data('id');
        let row = $(this).parent().parent();
        let cells = row.find('td');
        $('#first_name').val(cells.eq(0).text());
        $('#last_name').val(cells.eq(1).text());
        $('#fullname').val(cells.eq(2).text());
        $('#email').val(cells.eq(3).text());
        $('#address').val(cells.eq(4).text());
        $('#contact').val(cells.eq(5).text());
        $("#bttHello").val('更新');
    });

    // 绑定删除按钮事件
    $(".delete-btn").click(function () {
        if (confirm('确认删除该学生数据?')) {
            let deleteId = $(this).data('id');
            $.ajax({
                url: 'Servlet?action=delete',
                type: 'POST',
                dataType: 'json',
                data: JSON.stringify({id: deleteId}),
                contentType: 'application/json',
                success: function (result) {
                    renderStudentTable(result);
                }
            });
        }
    });
}

本地运行注意点

  • 启动GAE本地开发服务器后,所有数据会持久化保存在本地Datastore文件中,重启服务不会丢失数据
  • 所有Objectify的数据库操作必须在被ObjectifyFilter拦截的请求中执行,否则会抛出无会话异常
  • 实体类必须保留无参构造函数,否则Objectify无法反序列化数据

内容的提问来源于stack exchange,提问作者Beginner

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.18 21:54:03