这是目录
SpringBoot
输入java -version
得到我的java version "16.0.1"
。
cd到pom.xml
文件所在位置即项目根目录并执行指令./mvnw dependency:list
来查看引用版本:
- org.springframework.data:spring-data-jpa:2.5.2
- javax.validation:validation-api:2.0.1.Final
- com.alibaba:fastjson:1.2.78
- org.projectlombok:lombok:1.18.20
- org.springframework:spring-web:5.3.8
- org.springframework.boot:spring-boot:2.5.2
实体类
Media.java
一个很普通的实体类,包名省略。
package com.example.demo.entity;
import com.alibaba.fastjson.annotation.JSONField;
import java.io.Serializable;
import lombok.*;
import javax.persistence.*;
@SuppressWarnings({
"LombokEqualsAndHashCodeInspection"})
@EqualsAndHashCode
@ToString
@Getter
@Setter
@Entity
@Table(name = "media")
@AllArgsConstructor
@NoArgsConstructor
public class Media implements Serializable
{
@Id
@JSONField(ordinal = 1)
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id", insertable = false, updatable = false)
private Integer id;
@JSONField(ordinal = 2)
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "book_id", updatable = false)
private Integer bookId;
@JSONField(ordinal = 3)
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "url", length = 128)
private String url;
}
持久层
IMediaRepository.java
一个啥也没有的接口。
package com.example.demo.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import com.example.demo.entity.Media;
public interface IMediaRepository extends
JpaRepository<Media, Integer>,
JpaSpecificationExecutor<Media>
{
}
服务
写一些接口。
IService.java
package com.example.demo.service;
import org.springframework.lang.Nullable;
public interface IService<T, K>
{
@Nullable
T get(K primaryKey);
@Nullable
T addOrUpdate(T obj);
boolean delete(K primaryKey);
}
IQueryService.java
package com.example.demo.service;
import java.util.*;
public interface IQueryService<T>
{
List<T> find(int index, int size);
long count();
List<T> find(int index, int size, Map<String, String> colAndPatterns);
long count(Map<String, String> colAndPatterns);
}
BaseService.java
抽象服务类。
可以这样写
package com.example.demo.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.jpa.repository.*;
import com.example.demo.util.Common;
import javax.persistence.criteria.*;
import javax.validation.constraints.*;
import java.util.*;
public abstract class BaseService<T, K, R extends JpaRepository<T, K> & JpaSpecificationExecutor<T>>
implements IService<T, K>, IQueryService<T>
{
@Autowired
protected R repo; // 让@Autowired自己找合适的类注入
...
@SuppressWarnings({
"UnnecessarySemicolon", "OverlyBroadCatchBlock"})
@Override
public final T addOrUpdate(@NotNull final T obj)
{
T ret = null;
if (canAddOrUpdate(obj))
{
try
{
ret = repo.saveAndFlush(obj);
}
catch (Exception e)
{
e.printStackTrace();
}
}
return ret;
}
protected abstract boolean canAddOrUpdate(final T obj);
}
还可以这样写
感觉这个比上面那种要好一点,减少一个泛型参数。
package com.example.demo.service;
public abstract class BaseService<T, K> implements IService<T, K>, IQueryService<T>
{
@Autowired
protected JpaRepository<T, K> repo;
@Autowired
protected JpaSpecificationExecutor<T> queryRepo; // 少一个泛型参数,多注入一次
...
@SuppressWarnings({
"UnnecessarySemicolon", "OverlyBroadCatchBlock"})
@Override
public final T addOrUpdate(@NotNull final T obj)
{
T ret = null;
if (canAddOrUpdate(obj))
{
try
{
ret = repo.saveAndFlush(obj);
}
catch (Exception e)
{
e.printStackTrace();
}
finally
{
;
}
}
return ret;
}
protected abstract boolean canAddOrUpdate(final T obj);
}
MediaService.java
服务类指定了类参数,然后实现之前的BaseService的抽象方法。
package com.example.demo.service;
import org.springframework.stereotype.Service;
import com.example.demo.entity.Media;
import com.example.demo.repository.IMediaRepository;
@Service(value = "mediaService")
public class MediaService extends BaseService<Media, Integer, IMediaRepository>
{
}
或
```java
package com.example.demo.service;
import org.springframework.stereotype.Service;
import com.example.demo.entity.Media;
@Service(value = "mediaService")
public class MediaService extends BaseService<Media, Integer>
{
...
}
控制器
IController.java
接口
package com.example.demo.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
public interface IController<T, K>
{
@RequestMapping(method = RequestMethod.POST)
String add(T body);
@RequestMapping(method = RequestMethod.PUT)
String update(T body);
@RequestMapping(method = RequestMethod.DELETE)
String delete(K id);
@RequestMapping(value = "/list", method = RequestMethod.GET)
String gets(Integer index, Integer size);
@RequestMapping(method = RequestMethod.GET)
String get(K id);
}
BaseController.java
package com.example.demo.controller;
import com.alibaba.fastjson.JSON;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import com.example.demo.service.BaseService;
@RestController
public abstract class BaseController<T, K> implements IController<T, K>
{
@Autowired
protected BaseService<T, K> service;
@Override
public String add(@RequestBody final T body)
{
return JSON.toJSONString(service.addOrUpdate(body));
}
...
}
MediaController.java
方法头顶上的注解也是可以继承的,但是参数注解重写方法就得重新再加一遍,忽略这一点造成的bug很低级。
package com.example.demo.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.example.demo.entity.Media;
@RestController
@RequestMapping("/media")
public class MediaController extends BaseController<Media, Integer>
{
}
测试接口
跑通。