AdminInfoController如下:
//个人中心
@RestController
public class AdminInfoController {
@Autowired
private IAdminService adminService;
@ApiOperation(value = "更新当前用户信息")
@PutMapping("/admin/info")
public RespBean updateAdmin(@RequestBody Admin admin, Authentication authentication){
if (adminService.updateById(admin)){
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(admin, null, authentication.getAuthorities()));
return RespBean.success("更新成功");
}
return RespBean.error("更新失败");
}
@ApiOperation(value = "更新用户密码")
@PutMapping("/admin/pass")
public RespBean updateAdminPassword(@RequestBody Map<String,Object> info){
String oldPass = (String) info.get("oldPass");
String pass = (String) info.get("pass");
Integer adminId = (Integer) info.get("adminId");
return adminService.updateAdminPassword(oldPass, pass, adminId);
}
@ApiOperation(value = "更新用户头像")
@PostMapping("/admin/userface")
public RespBean updateAdminUserFace(MultipartFile file, Integer id, Authentication authentication){
String[] filePath = FastDFSUtils.upload(file);
String url=FastDFSUtils.getTrackerUrl()+filePath[0]+"/"+filePath[1];
return adminService.updateAdminUserFace(url,id,authentication);
}
}
更新用户头像(updateAdminUserFace)功能用到了FastDFS,其工具类为FastDFSUtils,如下:
public class FastDFSUtils {
private static Logger logger= LoggerFactory.getLogger(FastDFSUtils.class);
static {
try {
String filePath=new ClassPathResource("fdfs_client.conf").getFile().getAbsolutePath();
ClientGlobal.init(filePath);
} catch (Exception e) {
logger.error("初始化FastDFS失败", e.getMessage());
}
}
//上传文件
public static String[] upload(MultipartFile file){
String filename = file.getOriginalFilename();
logger.info("文件名:", filename);
StorageClient storageClient=null;
String[] uploadResults=null;
try {
storageClient=getStorageClient();
uploadResults = storageClient.upload_file(file.getBytes(), filename.substring(filename.lastIndexOf(".") + 1), null);
} catch (Exception e) {
logger.error("上传文件失败", e.getMessage());
}
if (uploadResults==null){
logger.error("上传失败", storageClient.getErrorCode());
}
return uploadResults;
}
//获取文件信息
public static FileInfo getFileInfo(String groupName, String remoteFileName){
StorageClient storageClient=null;
try {
storageClient = getStorageClient();
return storageClient.get_file_info(groupName,remoteFileName);
} catch (Exception e) {
logger.error("文件信息获取失败", e.getMessage());
}
return null;
}
//下载文件
public static InputStream downloadFile(String groupName, String remoteFileName){
StorageClient storageClient=null;
try {
storageClient = getStorageClient();
byte[] fileByte = storageClient.download_file(groupName, remoteFileName);
InputStream inputStream=new ByteArrayInputStream(fileByte);
return inputStream;
} catch (Exception e) {
logger.error("文件下载失败", e.getMessage());
}
return null;
}
//删除文件
public static void deleteFile(String groupName, String remoteFileName){
StorageClient storageClient=null;
try {
storageClient = getStorageClient();
storageClient.delete_file(groupName,remoteFileName);
} catch (Exception e) {
logger.error("文件删除失败", e.getMessage());
}
}
//获取文件路径
public static String getTrackerUrl(){
TrackerClient trackerClient=new TrackerClient();
TrackerServer trackerServer=null;
StorageServer storeStorage=null;
try {
trackerServer=trackerClient.getTrackerServer();
storeStorage=trackerClient.getStoreStorage(trackerServer);
} catch (Exception e) {
logger.error("文件路径获取失败", e.getMessage());
}
return "http://"+storeStorage.getInetSocketAddress().getHostString()+":8888/";
}
private static StorageClient getStorageClient() throws IOException {
TrackerServer trackerServer = getTrackerServer();
StorageClient storageClient=new StorageClient(trackerServer, null);
return storageClient;
}
private static TrackerServer getTrackerServer() throws IOException {
TrackerClient trackerClient=new TrackerClient();
TrackerServer trackerServer=trackerClient.getTrackerServer();
return trackerServer;
}
}
静态代码块里加载了fdfs_client.conf,如下:
#连接超时
connect_timeout = 2
#网络超时
network_timeout = 30
#编码格式
charset = UTF-8
#tracker端口号
http.tracker_http_port = 8080
#防盗链功能
http.anti_steal_token = no
#秘钥
http.secret_key = FastDFS1234567890
#tracker ip:端口号
tracker_server = 192.168.10.100:22122
#连接池配置
connection_pool.enabled = true
connection_pool.max_count_per_entry = 500
connection_pool.max_idle_time = 3600
connection_pool.max_wait_time_in_ms = 1000
上面代码中端口号什么的可能写的有问题。
更新用户头像的流程:把用户头像的图片文件(前端负责传给后端)上传到FastDFS,拿到访问该图片的url;把此url更新到t_admin表中;把此url返回给前端,前端就可以拿着此url直接访问FastDFS上的资源。
自定义反序列化。
先看一下下面这个接口方法:
@ApiOperation(value = "获取当前登录用户的信息")
@GetMapping("/admin/info")
public Admin getAdminInfo(Principal principal){
if (principal==null){
return null;
}
String username = principal.getName();
Admin admin=adminService.getAdminByUserName(username);
admin.setPassword(null);
admin.setRoles(adminService.getRoles(admin.getId()));
return admin;
}
返回给前端的是如下图所示的JSON串,似乎多了几个字段,原因是Admin类实现了UserDetails接口。
再看一下Admin类:
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@TableName("t_admin")
@ApiModel(value="Admin对象", description="")
public class Admin implements Serializable, UserDetails {
private static final long serialVersionUID = 1L;
@ApiModelProperty(value = "id")
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
@ApiModelProperty(value = "姓名")
private String name;
@ApiModelProperty(value = "手机号码")
private String phone;
@ApiModelProperty(value = "住宅电话")
private String telephone;
@ApiModelProperty(value = "联系地址")
private String address;
@ApiModelProperty(value = "是否启用")
@Getter(AccessLevel.NONE)
private Boolean enabled;
@ApiModelProperty(value = "用户名")
private String username;
@ApiModelProperty(value = "密码")
private String password;
@ApiModelProperty(value = "用户头像")
private String userFace;
@ApiModelProperty(value = "备注")
private String remark;
@ApiModelProperty(value = "角色")
@TableField(exist = false)
private List<Role> roles;
@Override
@JsonDeserialize(using = CustomAuthorityDeserializer.class)
public Collection<? extends GrantedAuthority> getAuthorities() {
List<SimpleGrantedAuthority> authorities=roles
.stream()
.map(role -> new SimpleGrantedAuthority(role.getName()))
.collect(Collectors.toList());
return authorities;
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return enabled;
}
}
从上面的测试可以看到,返回给前端时的默认JSON序列化方式是可以的。
但当更新用户信息时,前端可能会传authorities字段给后端,但后端接口方法传入的是Admin,显然Admin类无法“正常”接收,也就是默认的JSON反序列化方式会报错。因此需要自定义反序列化器CustomAuthorityDeserializer。
public class CustomAuthorityDeserializer extends JsonDeserializer {
@Override
public Object deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
ObjectMapper mapper = (ObjectMapper) jsonParser.getCodec();
JsonNode jsonNode = mapper.readTree(jsonParser);
List<GrantedAuthority> grantedAuthorities=new LinkedList<>();
Iterator<JsonNode> elements = jsonNode.elements();
while(elements.hasNext()){
JsonNode next = elements.next();
JsonNode authority = next.get("authority");
grantedAuthorities.add(new SimpleGrantedAuthority(authority.asText()));
}
return grantedAuthorities;
}
}