Compare commits

..

2 Commits

18 changed files with 181 additions and 49 deletions

View File

@ -6,6 +6,7 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import javax.annotation.Resource; import javax.annotation.Resource;
@ -36,4 +37,11 @@ public class RedisConfig {
return template; return template;
} }
@Bean
public StringRedisTemplate stringRedisTemplate() {
StringRedisTemplate template = new StringRedisTemplate();
template.setConnectionFactory(factory);
return template;
}
} }

View File

@ -1,8 +1,10 @@
package cn.edu.hfut.rmdjzz.projectmanagement.config; package cn.edu.hfut.rmdjzz.projectmanagement.config;
import cn.edu.hfut.rmdjzz.projectmanagement.utils.http.IPAddress;
import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.*; import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import lombok.SneakyThrows; import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@ -25,11 +27,32 @@ public class SerializeConfig {
@Bean @Bean
public ObjectMapper objectMapper() { public ObjectMapper objectMapper() {
ObjectMapper om = new ObjectMapper(); ObjectMapper om = new ObjectMapper();
om.registerModule(javaTimeModule());
om.registerModule(customClassModule());
return om;
}
@SuppressWarnings({"Convert2Diamond", "NullableProblems", "rawtypes"})
@Bean
public Converter<String, Map> mapConverter() {
return new Converter<String, Map>() {
@Autowired
private ObjectMapper objectMapper;
@SneakyThrows
@Override
public Map convert(String source) {
return objectMapper.readValue(source, Map.class);
}
};
}
private JavaTimeModule javaTimeModule() {
JavaTimeModule javaTimeModule = new JavaTimeModule(); JavaTimeModule javaTimeModule = new JavaTimeModule();
//LocalDataTime //LocalDateTime
javaTimeModule.addSerializer(LocalDateTime.class, new JsonSerializer<>() { javaTimeModule.addSerializer(LocalDateTime.class, new JsonSerializer<>() {
@Override @Override
public void serialize(LocalDateTime value, JsonGenerator gen, SerializerProvider serializers) throws IOException { public void serialize(LocalDateTime value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
@ -77,24 +100,27 @@ public class SerializeConfig {
} }
}); });
om.registerModule(javaTimeModule); return javaTimeModule;
return om;
} }
@SuppressWarnings({"Convert2Diamond", "NullableProblems", "rawtypes"}) //TODO: Redis可能改成tostringSerializer
@Bean private SimpleModule customClassModule() {
public Converter<String, Map> mapConverter() { SimpleModule customClassModule = new SimpleModule("CustomClassModule");
return new Converter<String, Map>() { customClassModule.addSerializer(IPAddress.class, new JsonSerializer<>() {
@Autowired
private ObjectMapper objectMapper;
@SneakyThrows
@Override @Override
public Map convert(String source) { public void serialize(IPAddress value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
return objectMapper.readValue(source, Map.class); if (value != null) {
gen.writeString(value.toString());
} }
}; }
});
customClassModule.addDeserializer(IPAddress.class, new JsonDeserializer<>() {
@Override
public IPAddress deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
return IPAddress.of(Long.decode(p.getValueAsString()));
}
});
return customClassModule;
} }
} }

View File

@ -32,6 +32,7 @@ public class WebConfig implements WebMvcConfigurer {
.excludePathPatterns("/hello", "/error") //测试 .excludePathPatterns("/hello", "/error") //测试
.excludePathPatterns("/staff/login") //登录 .excludePathPatterns("/staff/login") //登录
.excludePathPatterns("/swagger-ui.html", "/swagger-resources/**", "/swagger-ui/**", .excludePathPatterns("/swagger-ui.html", "/swagger-resources/**", "/swagger-ui/**",
"/v2/**", "/v3/**", "/webjars/**", "/doc.html"); //swagger "/v2/**", "/v3/**", "/webjars/**", "/doc.html") //swagger
.excludePathPatterns("/favicon.ico", "/public/**"); //静态资源
} }
} }

View File

@ -46,7 +46,7 @@ public class AnnouncementController {
if (projectGroupService.getProjectAccessLevel(token, projectId) == 0) { if (projectGroupService.getProjectAccessLevel(token, projectId) == 0) {
throw new ForbiddenException(IProjectGroupService.UNABLE_TO_ACCESS_PROJECT); throw new ForbiddenException(IProjectGroupService.UNABLE_TO_ACCESS_PROJECT);
} }
return ResponseMap.ofSuccess(announcementService.getAnnouncementById(announcementId)); return ResponseMap.ofSuccess(announcementService.getAnnouncementById(projectId, announcementId));
} }
@SneakyThrows @SneakyThrows

View File

@ -2,7 +2,6 @@ package cn.edu.hfut.rmdjzz.projectmanagement.controller;
import cn.edu.hfut.rmdjzz.projectmanagement.entity.Staff; import cn.edu.hfut.rmdjzz.projectmanagement.entity.Staff;
import cn.edu.hfut.rmdjzz.projectmanagement.exception.BadRequestException; import cn.edu.hfut.rmdjzz.projectmanagement.exception.BadRequestException;
import cn.edu.hfut.rmdjzz.projectmanagement.exception.ForbiddenException;
import cn.edu.hfut.rmdjzz.projectmanagement.exception.TokenException; import cn.edu.hfut.rmdjzz.projectmanagement.exception.TokenException;
import cn.edu.hfut.rmdjzz.projectmanagement.service.IStaffService; import cn.edu.hfut.rmdjzz.projectmanagement.service.IStaffService;
import cn.edu.hfut.rmdjzz.projectmanagement.utils.FileUtils; import cn.edu.hfut.rmdjzz.projectmanagement.utils.FileUtils;
@ -12,12 +11,12 @@ import cn.edu.hfut.rmdjzz.projectmanagement.utils.http.ResponseMap;
import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.Parameter;
import lombok.SneakyThrows; import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.util.DigestUtils; import org.springframework.util.DigestUtils;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Objects; import java.util.Objects;
/** /**
@ -72,7 +71,8 @@ public class StaffController {
return ResponseMap.ofSuccess("成功导入" + successCount + "条数据"); return ResponseMap.ofSuccess("成功导入" + successCount + "条数据");
} }
@SneakyThrows //取消功能
/*@SneakyThrows
@GetMapping("/import/template") @GetMapping("/import/template")
public void downloadTemplate( public void downloadTemplate(
@RequestHeader(TokenUtils.HEADER_TOKEN) String token, @RequestHeader(TokenUtils.HEADER_TOKEN) String token,
@ -81,9 +81,18 @@ public class StaffController {
if (TokenUtils.getStaffGlobalLevel(token) > 2) { if (TokenUtils.getStaffGlobalLevel(token) > 2) {
throw new ForbiddenException(ForbiddenException.UNABLE_TO_OPERATE); throw new ForbiddenException(ForbiddenException.UNABLE_TO_OPERATE);
} }
if (FileUtils.downloadResource("static/账户导入模板.xlsx", response)) { if (FileUtils.downloadResource("static/public/账户导入模板.xlsx", response)) {
return; return;
} }
throw new BadRequestException(BadRequestException.OPERATE_FAILED); throw new BadRequestException(BadRequestException.OPERATE_FAILED);
}*/
@SneakyThrows
@GetMapping("/import/template")
@ResponseStatus(HttpStatus.SEE_OTHER)
public ResponseMap downloadTemplate() {
return ResponseMap.of(HttpStatus.SEE_OTHER.value(),
HttpStatus.SEE_OTHER.getReasonPhrase())
.put("URI","/public/账户导入模板.xlsx");
} }
} }

View File

@ -13,6 +13,7 @@ public class AnnouncementDTO {
private Long announcementId; private Long announcementId;
private Integer announcementPublisherId; private Integer announcementPublisherId;
private String announcementPublisherName; private String announcementPublisherName;
private Integer announcementPublisherAccessLevel;
private LocalDateTime announcementPublishTime; private LocalDateTime announcementPublishTime;
private String announcementTitle; private String announcementTitle;
private String announcementContent; private String announcementContent;

View File

@ -7,6 +7,8 @@ import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import java.util.Enumeration;
import java.util.Iterator;
/** /**
* @author * @author
@ -21,6 +23,14 @@ public class CorsInterceptor implements HandlerInterceptor {
response.setHeader("Access-Control-Allow-Methods", "*"); response.setHeader("Access-Control-Allow-Methods", "*");
response.setHeader("Access-Control-Allow-Headers", "Content-Type,Token"); response.setHeader("Access-Control-Allow-Headers", "Content-Type,Token");
response.setHeader("Access-Control-Allow-Credentials", "false"); response.setHeader("Access-Control-Allow-Credentials", "false");
//test
Enumeration<String> headerNames = request.getHeaderNames();
Iterator<String> nameIter = headerNames.asIterator();
while (nameIter.hasNext()) {
System.out.println(nameIter.next());
}
// 如果是OPTIONS则结束请求 // 如果是OPTIONS则结束请求
if (HttpMethod.OPTIONS.toString().equals(request.getMethod())) { if (HttpMethod.OPTIONS.toString().equals(request.getMethod())) {
response.setStatus(HttpStatus.OK.value()); response.setStatus(HttpStatus.OK.value());

View File

@ -14,5 +14,5 @@ import java.util.List;
public interface AnnouncementMapper extends BaseMapper<Announcement> { public interface AnnouncementMapper extends BaseMapper<Announcement> {
List<AnnouncementDTO> selectAnnouncementList(@Param("projectId") Integer projectId); List<AnnouncementDTO> selectAnnouncementList(@Param("projectId") Integer projectId);
AnnouncementDTO selectAnnouncementById(@Param("announcementId") Long announcementId); AnnouncementDTO selectAnnouncementById(@Param("projectId") Integer projectId, @Param("announcementId") Long announcementId);
} }

View File

@ -16,7 +16,7 @@ public interface IAnnouncementService extends IService<Announcement> {
List<AnnouncementDTO> getAnnouncementList(Integer projectId); List<AnnouncementDTO> getAnnouncementList(Integer projectId);
AnnouncementDTO getAnnouncementById(Long announcementId); AnnouncementDTO getAnnouncementById(Integer projectId, Long announcementId);
Boolean updateAnnouncement(String token, Integer projectId, Announcement announcement) throws ForbiddenException, BadRequestException; Boolean updateAnnouncement(String token, Integer projectId, Announcement announcement) throws ForbiddenException, BadRequestException;

View File

@ -28,7 +28,7 @@ public interface IProjectGroupService extends IService<ProjectGroup> {
Boolean removeMember(String token, Integer projectId, Integer targetId) throws ForbiddenException, BadRequestException; Boolean removeMember(String token, Integer projectId, Integer targetId) throws ForbiddenException, BadRequestException;
Boolean updateStaffPositions(String token, Integer projectId, Integer targetId, String positions) throws ForbiddenException; Boolean updateStaffPositions(String token, Integer projectId, Integer targetId, String positions) throws ForbiddenException, BadRequestException;
/** /**
* @return 0AccessLevel11 * @return 0AccessLevel11

View File

@ -31,8 +31,8 @@ public class AnnouncementServiceImpl extends ServiceImpl<AnnouncementMapper, Ann
} }
@Override @Override
public AnnouncementDTO getAnnouncementById(Long announcementId) { public AnnouncementDTO getAnnouncementById(Integer projectId, Long announcementId) {
return baseMapper.selectAnnouncementById(announcementId); return baseMapper.selectAnnouncementById(projectId, announcementId);
} }
@Override @Override
@ -64,8 +64,7 @@ public class AnnouncementServiceImpl extends ServiceImpl<AnnouncementMapper, Ann
throw new ForbiddenException(ForbiddenException.UNABLE_TO_OPERATE); throw new ForbiddenException(ForbiddenException.UNABLE_TO_OPERATE);
} }
Announcement rawAnnouncement = baseMapper.selectOne(Wrappers.<Announcement>lambdaQuery() Announcement rawAnnouncement = baseMapper.selectOne(Wrappers.<Announcement>lambdaQuery()
.select(Announcement::getProjectId) .select(Announcement::getProjectId, Announcement::getAnnouncementPublisherId)
.select(Announcement::getAnnouncementPublisherId)
.eq(Announcement::getAnnouncementId, announcementId) .eq(Announcement::getAnnouncementId, announcementId)
); );
if (!Objects.equals(projectId, rawAnnouncement.getProjectId())) { if (!Objects.equals(projectId, rawAnnouncement.getProjectId())) {

View File

@ -44,6 +44,9 @@ public class ProjectGroupServiceImpl extends ServiceImpl<ProjectGroupMapper, Pro
@Override @Override
public Boolean insertNewMember(String token, Integer projectId, String targetUsername, String positions) throws ForbiddenException, BadRequestException { public Boolean insertNewMember(String token, Integer projectId, String targetUsername, String positions) throws ForbiddenException, BadRequestException {
if (targetUsername.equals("root")) {
throw new BadRequestException(IStaffService.STAFF_DOES_NOT_EXIST);
}
int accessLevel = getProjectAccessLevel(token, projectId); int accessLevel = getProjectAccessLevel(token, projectId);
int targetLevel = 3; int targetLevel = 3;
@ -51,6 +54,9 @@ public class ProjectGroupServiceImpl extends ServiceImpl<ProjectGroupMapper, Pro
if (targetStaff == null) { if (targetStaff == null) {
throw new BadRequestException(IStaffService.STAFF_DOES_NOT_EXIST); throw new BadRequestException(IStaffService.STAFF_DOES_NOT_EXIST);
} }
if (getProjectAccessLevelIgnoreGlobalLevel(targetStaff.getStaffId(), projectId) != 0) {
throw new BadRequestException("该成员已经在本项目中");
}
if (accessLevel == 0) { if (accessLevel == 0) {
throw new ForbiddenException(IProjectGroupService.UNABLE_TO_ACCESS_PROJECT); throw new ForbiddenException(IProjectGroupService.UNABLE_TO_ACCESS_PROJECT);
@ -91,9 +97,12 @@ public class ProjectGroupServiceImpl extends ServiceImpl<ProjectGroupMapper, Pro
} }
@Override @Override
public Boolean updateStaffPositions(String token, Integer projectId, Integer targetId, String positions) throws ForbiddenException { public Boolean updateStaffPositions(String token, Integer projectId, Integer targetId, String positions) throws ForbiddenException, BadRequestException {
int accessLevel = getProjectAccessLevel(token, projectId); int accessLevel = getProjectAccessLevel(token, projectId);
int originTargetLevel = getProjectAccessLevelIgnoreGlobalLevel(targetId, projectId); int originTargetLevel = getProjectAccessLevelIgnoreGlobalLevel(targetId, projectId);
if (originTargetLevel == 0) {
throw new BadRequestException("该项目中不存在该成员");
}
int targetLevel = 3; int targetLevel = 3;
if (accessLevel == 0) { if (accessLevel == 0) {

View File

@ -9,6 +9,7 @@ import cn.edu.hfut.rmdjzz.projectmanagement.utils.BeanUtils;
import cn.edu.hfut.rmdjzz.projectmanagement.utils.MapBuilder; import cn.edu.hfut.rmdjzz.projectmanagement.utils.MapBuilder;
import cn.edu.hfut.rmdjzz.projectmanagement.utils.TimeUtils; import cn.edu.hfut.rmdjzz.projectmanagement.utils.TimeUtils;
import cn.edu.hfut.rmdjzz.projectmanagement.utils.TokenUtils; import cn.edu.hfut.rmdjzz.projectmanagement.utils.TokenUtils;
import cn.edu.hfut.rmdjzz.projectmanagement.utils.http.IPAddress;
import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@ -45,34 +46,35 @@ public class StaffServiceImpl extends ServiceImpl<StaffMapper, Staff> implements
@SuppressWarnings("ConstantConditions") @SuppressWarnings("ConstantConditions")
@Override @Override
public Map<String, Object> login(String requestIpAddress, String staffUsername, String password) throws BadRequestException, ForbiddenException { public Map<String, Object> login(String requestIpAddress, String staffUsername, String password) throws BadRequestException, ForbiddenException {
if (Boolean.FALSE.equals(redisTemplate.hasKey(requestIpAddress))) { String requestIpAddressHex = IPAddress.of(requestIpAddress).toString();
redisTemplate.opsForValue().set(requestIpAddress, 0, LOGIN_TRY_COUNT_TIMEOUT, TimeUnit.MINUTES); if (Boolean.FALSE.equals(redisTemplate.hasKey(requestIpAddressHex))) {
redisTemplate.opsForValue().set(requestIpAddressHex, 0, LOGIN_TRY_COUNT_TIMEOUT, TimeUnit.MINUTES);
} }
int loginCount = (int) redisTemplate.opsForValue().get(requestIpAddress); int loginCount = (int) redisTemplate.opsForValue().get(requestIpAddressHex);
if (loginCount >= LOGIN_MAX_TRY_COUNT) { if (loginCount >= LOGIN_MAX_TRY_COUNT) {
throw new ForbiddenException(String.format("还需要等待%s才能登录" throw new ForbiddenException(String.format("还需要等待%s才能登录"
, TimeUtils.secondsFormat(redisTemplate.getExpire(requestIpAddress)))); , TimeUtils.secondsFormat(redisTemplate.getExpire(requestIpAddressHex))));
} }
if (staffUsername == null || staffUsername.strip().length() == 0) if (staffUsername == null || staffUsername.strip().length() == 0)
//throw new BadRequestException("用户名为空"); //throw new BadRequestException("用户名为空");
throwLoginException(requestIpAddress, loginCount); throw loginException(requestIpAddressHex, loginCount);
if (!staffUsername.equals(staffUsername.replaceAll("[^a-zA-Z0-9]", ""))) if (!staffUsername.equals(staffUsername.replaceAll("[^a-zA-Z0-9]", "")))
//throw new BadRequestException("用户名格式错误"); //throw new BadRequestException("用户名格式错误");
throwLoginException(requestIpAddress, loginCount); throw loginException(requestIpAddressHex, loginCount);
if (password == null || password.trim().length() != 32) if (password == null || password.trim().length() != 32)
//throw new BadRequestException("密码格式错误"); //throw new BadRequestException("密码格式错误");
throwLoginException(requestIpAddress, loginCount); throw loginException(requestIpAddressHex, loginCount);
Staff staff = getOne(Wrappers.<Staff>lambdaQuery().eq(Staff::getStaffUsername, staffUsername)); Staff staff = getOne(Wrappers.<Staff>lambdaQuery().eq(Staff::getStaffUsername, staffUsername));
if (staff == null) if (staff == null)
//throw new BadRequestException(STAFF_DOES_NOT_EXIST); //throw new BadRequestException(STAFF_DOES_NOT_EXIST);
throwLoginException(requestIpAddress, loginCount); throw loginException(requestIpAddressHex, loginCount);
password = DigestUtils.md5DigestAsHex((password + staff.getStaffSalt()).getBytes()); password = DigestUtils.md5DigestAsHex((password + staff.getStaffSalt()).getBytes());
if (!staff.getStaffPassword().equals(password)) { if (!staff.getStaffPassword().equals(password)) {
throwLoginException(requestIpAddress, loginCount); throw loginException(requestIpAddressHex, loginCount);
} }
String token = TokenUtils.getToken(staff.getStaffUsername(), staff.getStaffId(), staff.getStaffGlobalLevel(), tokenDuration); String token = TokenUtils.getToken(staff.getStaffUsername(), staff.getStaffId(), staff.getStaffGlobalLevel(), tokenDuration);
redisTemplate.opsForValue().set( redisTemplate.opsForValue().set(
@ -80,15 +82,16 @@ public class StaffServiceImpl extends ServiceImpl<StaffMapper, Staff> implements
token, token,
Objects.requireNonNull(TokenUtils.getDuration(token)), TimeUnit.SECONDS Objects.requireNonNull(TokenUtils.getDuration(token)), TimeUnit.SECONDS
); );
redisTemplate.delete(requestIpAddressHex);
return new MapBuilder() return new MapBuilder()
.put(TokenUtils.HEADER_TOKEN, token) .put(TokenUtils.HEADER_TOKEN, token)
.putAll(BeanUtils.beanToMap(staff, false)) .putAll(BeanUtils.beanToMap(staff, false))
.build(); .build();
} }
private void throwLoginException(String requestIpAddress, int loginCount) throws BadRequestException { private BadRequestException loginException(String requestIpAddress, int loginCount) {
redisTemplate.opsForValue().set(requestIpAddress, ++loginCount, LOGIN_TRY_COUNT_TIMEOUT, TimeUnit.MINUTES); redisTemplate.opsForValue().set(requestIpAddress, ++loginCount, LOGIN_TRY_COUNT_TIMEOUT, TimeUnit.MINUTES);
throw new BadRequestException(String.format("登录失败,%d分钟内还有%d次登录机会", LOGIN_TRY_COUNT_TIMEOUT, LOGIN_MAX_TRY_COUNT - loginCount)); return new BadRequestException(String.format("登录失败,%d分钟内还有%d次登录机会", LOGIN_TRY_COUNT_TIMEOUT, LOGIN_MAX_TRY_COUNT - loginCount));
} }
@Override @Override

View File

@ -0,0 +1,43 @@
package cn.edu.hfut.rmdjzz.projectmanagement.utils.http;
import lombok.AllArgsConstructor;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
/**
* @author
* @since 2022/7/12 17:12
*/
@AllArgsConstructor(staticName = "of")
public class IPAddress {
private long ipHex;
public static IPAddress of(String ip) {
long ipHex = 0;
String[] split = ip.split("\\.");
for (String s : split) {
ipHex = (ipHex << 8) + Integer.parseInt(s);
}
return new IPAddress(ipHex);
}
public String getIpString() {
List<String> ipSectionList = new LinkedList<>();
long tempHex = ipHex;
int section;
while (tempHex > 0) {
section = (int) (tempHex & 0xFF);
ipSectionList.add(String.valueOf(section));
tempHex >>= 8;
}
Collections.reverse(ipSectionList);
return String.join(".", ipSectionList);
}
@Override
public String toString() {
return "#" + Long.toHexString(ipHex);
}
}

View File

@ -12,7 +12,7 @@
announcement_publish_time, announcement_publish_time,
announcement_title announcement_title
FROM announcement FROM announcement
JOIN (SELECT staff_id, staff_fullname FROM staff) s JOIN (SELECT staff_id, staff_fullname FROM staff) AS s
ON staff_id = announcement.announcement_publisher_id ON staff_id = announcement.announcement_publisher_id
WHERE is_deleted = 0 WHERE is_deleted = 0
AND project_id = #{projectId} AND project_id = #{projectId}
@ -22,12 +22,17 @@
SELECT announcement_id, SELECT announcement_id,
announcement_publisher_id, announcement_publisher_id,
s.staff_fullname AS announcement_publisher_name, s.staff_fullname AS announcement_publisher_name,
IFNULL(pg.project_access_level, 1) AS announcement_publisher_access_level,
announcement_publish_time, announcement_publish_time,
announcement_title, announcement_title,
announcement_content announcement_content
FROM announcement FROM announcement
JOIN (SELECT staff_id, staff_fullname FROM staff) s JOIN (SELECT staff_id, staff_fullname FROM staff) AS s
ON staff_id = announcement.announcement_publisher_id ON s.staff_id = announcement.announcement_publisher_id
LEFT JOIN (SELECT staff_id, project_access_level
FROM project_group
WHERE project_id = #{projectId}) AS pg
ON pg.staff_id = announcement_publisher_id
WHERE is_deleted = 0 WHERE is_deleted = 0
AND announcement_id = #{announcementId}; AND announcement_id = #{announcementId};
</select> </select>

View File

@ -1,9 +1,11 @@
package cn.edu.hfut.rmdjzz.projectmanagement; package cn.edu.hfut.rmdjzz.projectmanagement;
import cn.edu.hfut.rmdjzz.projectmanagement.utils.http.IPAddress;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import java.time.LocalDateTime; import java.time.LocalDateTime;
@ -15,14 +17,21 @@ import java.time.LocalDateTime;
public class RedisTests { public class RedisTests {
@Autowired @Autowired
private RedisTemplate<Object, Object> redisTemplate; private RedisTemplate<Object, Object> redisTemplate;
@Autowired
private StringRedisTemplate stringRedisTemplate;
@Test @Test
void test() { void test() {
System.out.println(redisTemplate.opsForValue().get("l1")); System.out.println(redisTemplate.opsForValue().get(0x15A2));
} }
@Test @Test
void testValue() { void testValue() {
redisTemplate.opsForValue().set("time", LocalDateTime.now()); redisTemplate.opsForValue().set("time", LocalDateTime.now());
} }
@Test
void stringTest() {
stringRedisTemplate.opsForValue().set(IPAddress.of("192.168.0.1").toString(),String.valueOf(2));
}
} }

View File

@ -1,12 +1,12 @@
package cn.edu.hfut.rmdjzz.projectmanagement; package cn.edu.hfut.rmdjzz.projectmanagement;
import cn.edu.hfut.rmdjzz.projectmanagement.utils.http.IPAddress;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.SneakyThrows; import lombok.SneakyThrows;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest;
import java.time.LocalDate;
import java.time.LocalDateTime; import java.time.LocalDateTime;
/** /**
@ -24,4 +24,13 @@ public class SerializeTests {
public void serializeTime() { public void serializeTime() {
System.out.println(objectMapper.readValue("1657166400", LocalDateTime.class)); System.out.println(objectMapper.readValue("1657166400", LocalDateTime.class));
} }
@SneakyThrows
@Test
public void serializeIPTest() {
IPAddress ip = IPAddress.of("192.108.1.1");
System.out.println(objectMapper.writeValueAsString(ip));
System.out.println(ip.getIpString());
System.out.println(objectMapper.readValue("0xc06c0101",IPAddress.class));
}
} }