سلام دوباره
چند روز پیش در حین انجام پروژه نیاز داشتم تا تغییرات بعضی از جدول ها رو بتونم نگه دارم تا بعدا بتونم بهشون مراجعه کنم. مثال خیلی واقعی این طوری میشه:
من تو برنامم به جدول به اسم setting دارم که از طریق کنسول مدیریتی قابل تغییر هستش، و برای اینکه بفهمم چه کسی در چه زمانی و چه اطلاعاتی رو عوض کرده چند راه بیشتر ندارم:
1- نوشتن تغییرات در فایل ( که جستجو کردن تو اون سخت هستش و باید بدونید کدوم فایل رو باید بگردید)
۲- ایجاد یک جدول در دیتابیس و نوشتن تغیییرات در اون جدول به صورت دستی
۳- استفاده از JPAدر برنامه
۴- استفاده از hibernate envers
ما در اینجا میخوایم در مورد hibernate envers و نحوه استفاده از اون تو spring boot توضیح بدهیم
خب خیلی کار سختی اصلا نیست و به جای توضیحات اضافه بریم کار رو شروع کنیم:
من تو مقاله قبلی نحوه ایجاد یک پروژه رو توضیح داده بودم که میتونید ببینید بعد از اینکه پروژه رو ایجاد کردید library زیر را اضافه کنید:
<dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-envers</artifactId> <version>6.1.4.Final</version> </dependency>
حالا باید entity رو که میخوایم روش تغییرات رو اعمال کنیم باید انتخاب کنیم که ما در این مثال میخوایم روی جدول setting این کار رو انجام بدیم. برای این کار اصلا کار سختی نداریم فقط ما @Audited رو بالای کلاس باید اضافه کنیم و اگه از flyway تو پروژه داریم استفاده میکنیم باید جدول ها رو طبق روال flyway بسازیم:
CREATE TABLE revinfo ( rev INTEGER AUTO_INCREMENT, revtstmp BIGINT, PRIMARY KEY (rev) );
خب این جدول اصلی هستش برای نگه داشتن تغییرات، و به نوعی مهمترین جدول برای ذخیره اطلاعات.
CREATE TABLE setting ( id BIGINT NOT NULL AUTO_INCREMENT, name VARCHAR(100) NOT NULL, value VARCHAR(100) NOT NULL, primary key (id) ); ALTER TABLE setting ADD CONSTRAINT uc_setting_name UNIQUE (name);
حالا جدول برای ذخیره تغییرات جدول setting
CREATE TABLE setting_aud ( id bigint NOT NULL, name VARCHAR(50), value VARCHAR(50), rev INTEGER NOT NULL, revtype tinyint NOT NULL, PRIMARY KEY (id, rev) );
خب کار ما تا ایحا تموم شد و وقتی تغییراتی رو اعمال کنید مشاهده میکنید که همه تغییرات داره تو جدول ثبت میشه،
اطلاعات مربوط له REVTYPE به شرح زیر هستش:
0-Add 1-Update 2-Delete
خب حالا باید entity مربوط به setting رو درست کنیم.
import org.hibernate.envers.AuditTable; import org.hibernate.envers.Audited; import javax.persistence.*; @Table(name = "setting") @Entity @Audited @AuditTable("setting_aud") public class Setting { @Id @GeneratedValue(strategy = GenerationType.AUTO) @Column(name = "id", nullable = false) private Long id; @Column(unique = true, length = 100, nullable = false) private String name; @Column(unique = false, length = 100, nullable = false) private String value; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getValue() { return value; } public void setValue(String value) { this.value = value; } }
همانطور که مشخص هستش ما فقط دو تا annotation به نام های (@Audited و @AuditTable ) رو اضافه کردیم , و هیج تغییر دیگه تو برنامه ندادیم!
Git address: https://github.com/mahdiShirinabadi/envers_test
خب تو پروژه میام که controller برای تست تعریف میکنیم و متد ها رو تست میکنیم.
import com.mahdi.evenrs.example.model.Setting;
import com.mahdi.evenrs.example.model.SettingRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import java.util.Optional;
@RestController
@RequestMapping("/v1/")
public class EndPoint {
@Autowired
SettingRepository settingRepository;
@PostMapping(path = "/new")
public @ResponseBody
String create(HttpServletRequest httpRequest,@RequestParam(value = "name", required = false) String name, // resid digital
@RequestParam("value") String value) {
Setting setting = new Setting();
setting.setName(name);
setting.setValue(value);
settingRepository.save(setting);
return "ok";
}
@PostMapping(path = "/update")
public @ResponseBody
String update(HttpServletRequest httpRequest,@RequestParam(value = "id", required = false) String id,@RequestParam(value = "name", required = false) String name, // resid digital
@RequestParam("value") String value) {
Optional<Setting> setting = settingRepository.findById(Long.parseLong(id));
setting.get().setName(name);
setting.get().setValue(value);
settingRepository.save(setting.get());
return "update";
}
@PostMapping(path = "/delete")
public @ResponseBody
String delete(HttpServletRequest httpRequest,@RequestParam(value = "id", required = false) String id, // resid digital
@RequestParam("value") String value) {
Optional<Setting> setting = settingRepository.findById(Long.parseLong(id));
settingRepository.delete(setting.get());
return "delete";
}
}
فایل SettingRepository هم میسازیم که بتونیم تو متد controller ازش استفاده کنیم
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface SettingRepository extends CrudRepository<Setting, Long> {
}
پروژه رو اجرا میکنیم و با postman اون رو اجرا میکنیم.
متد ها رو اجرا کردیم و حالا جدول setting_aud رو میبینیم.
همانظور که دیدن مشخص هستش که هر رمورد در چه زمانی اجرا شده است.
خب تو قسمت بعدی مبحث پیشرفته رو میگم خدمتتون.
موفق باشید، فعلا