头é¨ç»å½ç¶æ
shiroæ ç¾çå¼ç¨
ç±äºshiroæ ç¾ä¸æ¯htmlçåçæ ç¾ï¼æææ们éè¦å å¼å ¥ä¸ä¸ªé¢å¤çä¾èµï¼shiroçæ ç¾åº(thymeleafçæå±æ ç¾)ã
<dependency>
<groupId>com.github.theborakompanioni</groupId>
<artifactId>thymeleaf-extras-shiro</artifactId>
<version>2.0.0</version>
</dependency>
ä¾èµæ·»å 好ä¹åï¼ç¶åï¼æ们éè¦å¨â
âcom.fly.config.ShiroConfigâ
â ä¸åå§åä¸ä¸ï¼æ³¨å ¥å¯¹åºçBean, 页é¢æè½æ¸²æåºæ¥
//ç¨äºthymeleaf模æ¿ä½¿ç¨shiroæ ç¾,shiroæ¹è¨æ ç¾
@Bean
public ShiroDialect shiroDialect() {
return new ShiroDialect();
}
ç¶åå¨éè¦ä½¿ç¨shiroæ ç¾çhtml æ件ç头é¨æ·»å
<html xmlns:th="http://www.thymeleaf.org"
xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">
æ·»å 好ä¹åï¼å°±å¯ä»¥ä½¿ç¨â
â<shiro:user></shiro:user>â
â å°è¦æéæ§å¶çå 容å èµ·æ¥ï¼å½ç¶shiro æ ç¾è¿æå¾å¤
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLiQDOxEzX3xCZlhXam9VbsUmepNXZy9CXwJWZ3xCdh1mcvZ2Lc1zaHRGcWdUYuVzVa9GczoVdG1mWfVGc5RHLwIzX39GZhh2csATMflHLwEzX4xSZz91ZsAzMfRHLGZkRGZkRfJ3bs92YskmNhVTYykVNQJVMRhXVEF1X0hXZ0xiNx8VZ6l2cssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZuBnL3QjNyAjMyEDOzUDZjZTYyYzX3IDOzMTMzEzLcZDMyIDMy8CXn9Gbi9CXzV2Zh1WavwVbvNmLvR3YxUjLyM3Lc9CX6MHc0RHaiojIsJye.png)
ç¨æ·ä¿¡æ¯åå°sessionä¸
ç¨æ·ç»å½æåä¹åéè¦å°ç¨æ·çä¿¡æ¯ä¿åçsessionä¸ãæ们åªéè¦å¨ç¨æ·è®¤è¯çæ¹æ³ä¸â
âcom.fly.shiro.OAuth2Realmâ
ââ ç±»çâ
âdoGetAuthenticationInfoâ
â æ¹æ³ä¸å ä¸å¦ä¸è¯å¥ï¼
// å°ç»éä¿¡æ¯æ¾å¨session
SecurityUtils.getSubject().getSession().setAttribute("profile",profile);
ç»è¿å¦ä¸å¦ä¸è®¾ç½®æ们就å®ç°äºç»å½å¤´é¨ç¶æçæ§å¶
å®å个人信æ¯
ç¨æ·ä¸å¿
ç¨æ·ä¸å¿ä¸»è¦å°±ä¸¤ä¸ªï¼æåçè´´åææ¶èçè´´
æåçå¸åï¼â
âå¨è¿éæå
¥ä»£ç çcom.homework.controller.CenterController#centerâ
â æ¥è¯¢æ¡ä»¶åªæç¨æ·id
QueryWrapper<Post> wrapper = new QueryWrapper<Post>().eq("user_id", getProfileId())
.orderByDesc("created");
IPage<Map<String, Object>> pageData = postService.pageMaps(page, wrapper);
request.setAttribute("pageData", pageData);
æçæ¶è
IPage<Map<String, Object>> pageData = userCollectionService.
pageMaps(page, new QueryWrapper<UserCollection>()
.eq("user_id", getProfileId()).orderByDesc("created"));
postService.join(pageData, "post_id");
request.setAttribute("pageData", pageData);
åºæ¬è®¾ç½®
- tab åæ¢åæ¾çé®é¢ï¼ä¸ä¸ªé¡µé¢æå¤ä¸ªtabï¼å¦ä½è®©å¨éä¸tab ä¹åå·æ°ä¸ä¸¢å¤±åæ¥çtabéä¸é项å¢ï¼çæ¡æ¯å¨url åé¢å ä¸#ï¼è¿ç¸å½äºæ ç¾çææã
- å½åtab页æ ç¾å®ä¹ï¼
å¨â
âstatic/mods/user.jsâ
â æå¦ä¸è¯å¥ï¼
//æ¾ç¤ºå½åtab
if(location.hash){
element.tabChange('user', location.hash.replace(/^#/, ''));
}
element.on('tab(user)', function(){
var othis = $(this), layid = othis.attr('lay-id');
if(layid){
location.hash = layid;
}
});
æ们å¨â
âtemplates/common/static.htmlâ
â æ¾å ¥äºå¦ä¸ä»£ç ï¼å¹¶ä¿®æ¹ä¸ä¿¡æ¯
<script th:inline="javascript" th:if="${session.profile != null}">
layui.cache.page = '';
layui.cache.user = {
username: [[${session.profile.username}]]
,uid: [[${session.profile.id}]]
,avatar: [[${session.profile.avatar}]]
,experience: 0
,sex: [[${session.profile.gender}]]
};
layui.config({
version: "3.0.0",
base: '/mods/' //è¿éå®é
使ç¨æ¶ï¼å»ºè®®æ¹æç»å¯¹è·¯å¾
}).extend({
fly: 'index'
}).use('fly');
</script>
éè¿ä¸é¢ä»£ç ï¼æ们æåå§ålayuiçé¨åjs代ç ï¼é¡µé¢ä¸å¾å¤classæid çdiv å°±æ¥æäºç¹å®ççå¬æå ¶ä»ãå ¶ä¸å°±æ¥è´§æªåurl è·å#åé¢çæ ç¾ç¨äºtab åæ¾åè½ï¼è¿æ头åçä¸ä¼ åè½å°è£ çã
å ä¸äºä¸é¢ä»£ç ä¹åä½ ä¼åç°ç»å¸¸ä¼æ个å¼å¸¸çå¼¹æ¡ï¼é£æ¯æµè§å¨æ§å¶å°åç°å»è®¿é®ââ
â/message/numsâ
ââ çé¾æ¥ï¼å¨index.js æ件ä¸æ¾å° æ°æ¶æ¯éç¥ï¼æç §æ¥å£è¦æ±æ们修æ¹å°å为â
â/user/message/numsâ
â 并å¨æ·»å 该æ¥å£
@ResponseBody
@PostMapping("/message/nums")
public Object getMessNums() {
Map<Object, Object> result = new HashMap<>();
result.put("status", 0);
result.put("count", 3);
return result;
}
-
头å
头åä¸ä¼ æ¥å£ââ
âcom.fly.controller.CenterController#uploadâ
ââ,
头åä¸ä¼ æ ¸å¿ä»£ç
String orgName = file.getOriginalFilename();
log.info("ä¸ä¼ æ件å为ï¼" + orgName);
// è·ååç¼å
String suffixName = orgName.substring(orgName.lastIndexOf("."));
log.info("ä¸ä¼ çåç¼å为ï¼" + suffixName);
// æ件ä¸ä¼ åçè·¯å¾
String filePath = Constant.uploadDir;
if ("avatar".equalsIgnoreCase(type)) {
fileName = "/avatar/avatar_" + getProfileId() + suffixName;
} else if ("post".equalsIgnoreCase(type)) {
fileName = "post/post_" + DateUtil.format(new Date(), DatePattern.PURE_DATETIME_MS_FORMAT) + suffixName;
}
File dest = new File(filePath + fileName);
// æ£æ¥ç®å½æ¯å¦åå¨
if (!dest.getParentFile().exists()) {
dest.getParentFile().mkdir();
}
//ä¸ä¼ æ件
file.transferTo(dest);
log.info("ä¸ä¼ æåä¹åæ件çè·¯å¾={}", dest.getPath());
ç®åä¸ä¼ çå¾çæ们æ¯å°äºä¸ä¸ªæå®ç®å½ï¼ç¶ånginxæè tomcatæ¯å¯ä»¥è¯»åè¿ä¸ªç®å½çï¼æ以å¯ä»¥éè¿urlæ¥è®¿é®ï¼ä¸è¬æ¥è¯´æ们æå¾çä¸ä¼ å°äºåå¨æå¡ä¸ãè¿éå è¿æ ·å¼äºã
头åä¸ä¼ ä¹åï¼æ´æ°shiro ä¸ç头åä¿¡æ¯
AccountProfile profile = getProfile();
profile.setAvatar(url);
å¾çä¸ä¼ ä¹åæ´æ°å¾åä¿¡æ¯
-
å¯ç
å¯ç éç½®æ¥å£ââ
â æ¥å£ä»£ç æ¯è¾ç®åï¼âcom.fly.controller.CenterController#resetPwdâ
@ResponseBody
@PostMapping("/resetPwd")
public R restPwd(String nowpass, String pass) {
//æ¥è¯¢ç¨æ·
User user = userService.getById(getProfileId());
if (user == null || !nowpass.equals(user.getPassword())) {
return R.failed("å¯ç ä¸æ£ç¡®");
}
user.setPassword(pass);
boolean result = userService.updateById(user);
return R.ok(result);
}
å端页é¢å¨ â
â/user/setting.htmlâ
â ä¸
å表ï¼ç¼è¾å客
å表åç¼è¾å客æ¯åä¸ä¸ªé¡µé¢ï¼å端页é¢å±ç¤º
ajax 请æ±ä»£ç ï¼
$(function() {
layui.use('form', function() {
var form = layui.form;
//çå¬æ交
form.on('submit(post)', function (data) {
$.ajax({
url: '/user/post',
type: "POST",
data: data.field,
success: function (res) {
if (res.code == 0) {
layer.msg("æä½æå");
setTimeout(function () {
location.href="/post/" + res.data;
}, 1000);
} else {
layer.msg(res.msg);
}
}
});
return false;
});
});
});
åå°æ¥å£å¨â
âcom.fly.controller.PostControllerâ
âç±»ä¸ï¼
@ResponseBody
@PostMapping("/user/post")
public R postArticle(@Valid Post post, BindingResult bindingResult) {
if (bindingResult.hasErrors()) {
return R.failed(bindingResult.getFieldError().getDefaultMessage());
}
// æ°å¢æç«
if (post.getId() == null) {
post.setUserId(getProfileId());
post.setModified(new Date());
post.setCreated(new Date());
post.setCommentCount(0);
post.setEditMode(Constant.EDIT_HTML_MODEL);
post.setLevel(0);
post.setRecommend(false);
post.setViewCount(0);
post.setVoteDown(0);
post.setVoteUp(0);
post.setStatus(Constant.NORMAL_STATUS);
} else {
Post tempPost = postService.getById(post.getId());
if (tempPost.getUserId().equals(getProfileId())) {
return R.failed("ä¸æ¯èªå·±çå¸å");
}
}
postService.saveOrUpdate(post);
// TODO: 2018/12/13 ç»ææ订é
人åéæ¶æ¯
return R.ok(post.getId());
}
æ¾ç¤ºæ¸²æå客
æ们åå çæ¾ç¤ºå客å 容æ¯éè¿å¦ä¸æ ç¾æ¥æ¾ç¤ºç
<div class="detail-body photos" th:text="${post.content}"></div>
ä½è¿æ ·æ¾ç¤ºåºæ¥çå 容ææ¾åæ们é¢è§çä¸ä¸æ ·ï¼è¿éè¦ç»è¿layuiç渲æï¼æ以æ们è¦å ä¸ä¸æ®µjs代ç ãå¨bodyåé¢å ä¸ï¼templates/post/index.html:253ï¼
<script>
layui.use(['fly','face'],function () {
var $ = layui.$
,fly=layui.fly;
// å¦æä½ æ¯éç¨æ¨¡æ¿èªå¸¦çç¼è¾å¨ï¼ä½ éè¦å¼å¯ä»¥ä¸è¯å¥æ¥è§£æ
$('.detail-body').each(function () {
var othis = $(this), html = othis.html();
othis.html(fly.content(html));
});
åæåæ¾
ç¨æ·ç¼è¾å®å客ä¹åï¼ç¹å»æ交ä¿åä¹åå°±å¯ä»¥ è°ç¨â
â/user/postâ
ââ è¿è¡åæåæ¾ï¼å客çå°åâ
âcom.fly.controller.PostController#indexâ
âï¼ åæåæ¾ä¸»è¦åæï¼ç¨æ·ï¼å类以åè¯è®ºä¿¡æ¯ï¼æ ¸å¿ä»£ç å¦ä¸ï¼
Map<String, Object> post = postService.getMap(new QueryWrapper<Post>().eq("id", id));
userService.join(post, "user_id");
categoryService.join(post, "category_id");
Assert.notNull(post, "该æç« å·²è¢«å é¤");
req.setAttribute("post", post);
req.setAttribute("currentCategoryId", post.get("category_id"));
Page<Comment> page = new Page<>();
page.setCurrent(current);
page.setSize(size);
IPage<Map<String, Object>> pageData = commentService.pageMaps(page, new QueryWrapper<Comment>()
.eq("post_id", id)
.orderByDesc("created"));
userService.join(pageData, "user_id");
commentService.join(pageData, "parent_id");
req.setAttribute("pageData", pageData);
å端页é¢å¨ â
âtemplates/post/index.htmlâ
â é¨å代ç å¦ä¸ï¼
页é¢ææå¦ä¸ï¼
ç¨æ·ä¸»é¡µ
å客è¯è®ºåè½
ç¨æ·è¯è®ºè¡¨ï¼
CREATE TABLE `comment` (
`id` bigint(32) NOT NULL AUTO_INCREMENT COMMENT '主é®ID',
`content` longtext NOT NULL COMMENT 'è¯è®ºçå
容',
`parent_id` bigint(32) DEFAULT NULL COMMENT 'åå¤çè¯è®ºID',
`post_id` bigint(32) NOT NULL COMMENT 'è¯è®ºçå
容ID',
`user_id` bigint(32) NOT NULL COMMENT 'è¯è®ºçç¨æ·ID',
`vote_up` int(11) unsigned NOT NULL DEFAULT '0' COMMENT 'â顶âçæ°é',
`vote_down` int(11) unsigned NOT NULL DEFAULT '0' COMMENT 'â踩âçæ°é',
`level` tinyint(2) unsigned NOT NULL DEFAULT '0' COMMENT '置顶ç级',
`status` tinyint(2) DEFAULT NULL COMMENT 'è¯è®ºçç¶æ',
`created` datetime NOT NULL COMMENT 'è¯è®ºçæ¶é´',
`modified` datetime DEFAULT NULL COMMENT 'è¯è®ºçæ´æ°æ¶é´',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4;
å端æ¥å£ä»£ç å¨â
âå¨è¿éæå
¥ä»£ç çâ
â
@ResponseBody
@PostMapping("/user/post/comment")
public R commentAdd(@Valid Comment comment, BindingResult bindingResult) {
Post post = postService.getById(comment.getPostId());
Assert.isTrue(post != null, "该å¸å已被å é¤");
comment.setUserId(getProfileId());
comment.setCreated(new Date());
comment.setModified(new Date());
comment.setStatus(Constant.NORMAL_STATUS);
// TODO è®°å½å¨ä½
// TODO éç¥ä½è
commentService.save(comment);
return R.ok(null);
}
å端页é¢å¨ â
âtemplates/post/index.htmlâ
â æ交è¯è®ºä»£ç å¦ä¸ï¼
ajax 代ç å¦ä¸ï¼
.use(['fly','face'],function () {
var $ = layui.$
,fly=layui.fly;
// å¦æä½ æ¯éç¨æ¨¡æ¿èªå¸¦çç¼è¾å¨ï¼ä½ éè¦å¼å¯ä»¥ä¸è¯å¥æ¥è§£æ
$('.detail-body').each(function () {
var othis = $(this), html = othis.html();
othis.html(fly.content(html));
});
var form = layui.form;
//çå¬æ交
form.on('submit(comment)', function (data) {
$.ajax({
url:'/user/post/comment',
data: data.field,
type:'POST',
success: function (res) {
if (res.code == 0) {
layer.msg('æä½æå');
setTimeout(function () {
location.reload();
}, 1000);
} else {
layer.msg(res.msg);
}
}
});
return false;
});
});
é ç½®å¼æ¥è¯·æ±ç»å½è¿æ»¤å¨
å¨æ们shiroConfigä¸ï¼æ们é ç½®äºéajaxç请æ±ç´æ¥è·³è½¬å°ç»å½é¡µé¢ï¼ä½æ¯åéçajax请æ±åä¸è½å¤çã
å¦æªç»å½ç¶æä¸ç´æ¥è¯è®ºææ¡£ï¼æ们åºè¯¥ç»åº 请å ç»å½ çæ示ã
å¨shiroä¸æå¾å¤è¿æ»¤å¨ãå ¶ä¸org.apache.shiro.web.filter.authc.UserFilter
å¨æ¤æ们继æ¿UserFilterç¶åéåredirectToLoginæ¹æ³ã
public class AuthFilter extends UserFilter {
@Override
protected void redirectToLogin(ServletRequest servletRequest, ServletResponse response) throws IOException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
// å¼æ¥è¯·æ±è¦å
ç»å½
String header = request.getHeader("X-Requested-With");
if (header != null && "XMLHttpRequest".equals(header)) {
Subject subject = SecurityUtils.getSubject();
if (!subject.isAuthenticated()) {
response.setContentType("application/json;charset=UTF-8");
response.getWriter().print(JSONUtil.toJsonStr(R.failed("请å
ç»å½!")));
} else {
super.redirectToLogin(servletRequest, response);
}
}
}
}
ç¶åå¨â
âcom.fly.config.ShiroConfigâ
âä¸æ³¨å ¥AuthFilter çBean
@Bean
public AuthFilter authFilter(){
return new AuthFilter();
}
å客æ¶èåè½
ç±äºæ们æ¶èæé®æ¯éè¿jså¨æçæçï¼æ以æ们å å¨htmlä¸å®ä¹å¥½åæ¾æ¶èæé®çdivï¼id 为â
âLAY_jieAdminâ
â
å¨static/mods/jie.js ä¸
var asyncRender = function () {
var div = $('.fly-admin-box'), jieAdmin = $('#LAY_jieAdmin');
//æ¥è¯¢å¸åæ¯å¦æ¶è
if (jieAdmin[0] && layui.cache.user.uid != -1) {
$.post("/user/post/collection/find",
{postId: div.data('id')}, function (res) {
console.log("--------------")
jieAdmin.append('<span class="layui-btn layui-btn-xs jie-admin ' + (res.data.collection ? 'layui-btn-danger' : '') + '" type="collect" data-type="' + (res.data.collection ? 'remove' : 'add') + '">' + (res.data.collection ? 'åæ¶æ¶è' : 'æ¶è') + '</span>');
});
}
}();
å ¶ä¸â
âlayui.cache.user.uidâ
ââ æ¯å¨templates/common/static.html ä¸å®ä¹çãä»ä¸è¿°ä»£ç ä¸æ们å¯ä»¥çåºï¼js 代ç æ ¹æ®å端çè¿åå¼å¨æççæ æ¶è or åæ¶æ¶è
å端æ¥å£å¦ä¸ï¼
@ResponseBody
@PostMapping("/user/post/collection/find")
public R collectionFind(String postId) {
int count = userCollectionService.count(new QueryWrapper<UserCollection>()
.eq("post_id", postId)
.eq("user_id", getProfileId()));
return R.ok(MapUtil.of("collection", count > 0));
}
æé®ç¹å»ææçå®ç°ä»£ç å¦ä¸ï¼
,collect: function(div){
var othis = $(this), type = othis.data('type');
fly.json('/user/post/collection/'+ type +'/', {
postId: div.data('id')
}, function(res){
if(type === 'add'){
othis.data('type', 'remove').html('åæ¶æ¶è').addClass('layui-btn-danger');
} else if(type === 'remove'){
othis.data('type', 'add').html('æ¶è').removeClass('layui-btn-danger');
}
});
}
};
å端代ç æ¯è¾ç®åï¼åè§ï¼â
âcom.fly.controller.PostControllerâ
â ä¸çç¸å ³æ¹æ³ã
ææå¾ï¼