").append(n.parseHTML(a)).find(d):a)}).complete(c&&function(a,b){g.each(c,e||[a.responseText,b,a])}),this},n.expr.filters.animated=function(a){return n.grep(n.timers,function(b){return a===b.elem}).length};var dd=a.document.documentElement;function ed(a){return n.isWindow(a)?a:9===a.nodeType?a.defaultView||a.parentWindow:!1}n.offset={setOffset:function(a,b,c){var d,e,f,g,h,i,j,k=n.css(a,"position"),l=n(a),m={};"static"===k&&(a.style.position="relative"),h=l.offset(),f=n.css(a,"top"),i=n.css(a,"left"),j=("absolute"===k||"fixed"===k)&&n.inArray("auto",[f,i])>-1,j?(d=l.position(),g=d.top,e=d.left):(g=parseFloat(f)||0,e=parseFloat(i)||0),n.isFunction(b)&&(b=b.call(a,c,h)),null!=b.top&&(m.top=b.top-h.top+g),null!=b.left&&(m.left=b.left-h.left+e),"using"in b?b.using.call(a,m):l.css(m)}},n.fn.extend({offset:function(a){if(arguments.length)return void 0===a?this:this.each(function(b){n.offset.setOffset(this,a,b)});var b,c,d={top:0,left:0},e=this[0],f=e&&e.ownerDocument;if(f)return b=f.documentElement,n.contains(b,e)?(typeof e.getBoundingClientRect!==L&&(d=e.getBoundingClientRect()),c=ed(f),{top:d.top+(c.pageYOffset||b.scrollTop)-(b.clientTop||0),left:d.left+(c.pageXOffset||b.scrollLeft)-(b.clientLeft||0)}):d},position:function(){if(this[0]){var a,b,c={top:0,left:0},d=this[0];return"fixed"===n.css(d,"position")?b=d.getBoundingClientRect():(a=this.offsetParent(),b=this.offset(),n.nodeName(a[0],"html")||(c=a.offset()),c.top+=n.css(a[0],"borderTopWidth",!0),c.left+=n.css(a[0],"borderLeftWidth",!0)),{top:b.top-c.top-n.css(d,"marginTop",!0),left:b.left-c.left-n.css(d,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||dd;while(a&&!n.nodeName(a,"html")&&"static"===n.css(a,"position"))a=a.offsetParent;return a||dd})}}),n.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(a,b){var c=/Y/.test(b);n.fn[a]=function(d){return W(this,function(a,d,e){var f=ed(a);return void 0===e?f?b in f?f[b]:f.document.documentElement[d]:a[d]:void(f?f.scrollTo(c?n(f).scrollLeft():e,c?e:n(f).scrollTop()):a[d]=e)},a,d,arguments.length,null)}}),n.each(["top","left"],function(a,b){n.cssHooks[b]=Mb(l.pixelPosition,function(a,c){return c?(c=Kb(a,b),Ib.test(c)?n(a).position()[b]+"px":c):void 0})}),n.each({Height:"height",Width:"width"},function(a,b){n.each({padding:"inner"+a,content:b,"":"outer"+a},function(c,d){n.fn[d]=function(d,e){var f=arguments.length&&(c||"boolean"!=typeof d),g=c||(d===!0||e===!0?"margin":"border");return W(this,function(b,c,d){var e;return n.isWindow(b)?b.document.documentElement["client"+a]:9===b.nodeType?(e=b.documentElement,Math.max(b.body["scroll"+a],e["scroll"+a],b.body["offset"+a],e["offset"+a],e["client"+a])):void 0===d?n.css(b,c,g):n.style(b,c,d,g)},b,f?d:void 0,f,null)}})}),n.fn.size=function(){return this.length},n.fn.andSelf=n.fn.addBack,"function"==typeof define&&define.amd&&define("jquery",[],function(){return n});var fd=a.jQuery,gd=a.$;return n.noConflict=function(b){return a.$===n&&(a.$=gd),b&&a.jQuery===n&&(a.jQuery=fd),n},typeof b===L&&(a.jQuery=a.$=n),n});
diff --git a/WebRoot/js/pintuer.js b/WebRoot/js/pintuer.js
deleted file mode 100644
index 69ad430..0000000
--- a/WebRoot/js/pintuer.js
+++ /dev/null
@@ -1,503 +0,0 @@
-$(function(){
- $(".win-homepage").click(function(){
- if(document.all){
- document.body.style.behavior = 'url(#default#homepage)';
- document.body.setHomePage(document.URL);
- }else{alert("设置首页失败,请手动设置!");}
- });
- $(".win-favorite").click(function(){
- var sURL=document.URL;
- var sTitle=document.title;
- try {window.external.addFavorite(sURL, sTitle);}
- catch(e){
- try{window.sidebar.addPanel(sTitle, sURL, "");}
- catch(e){alert("加入收藏失败,请使用Ctrl+D进行添加");}
- }
- });
- $(".win-forward").click(function(){
- window.history.forward(1);
- });
- $(".win-back").click(function(){
- window.history.back(-1);
- });
- $(".win-backtop").click(function(){$('body,html').animate({scrollTop:0},1000);return false;});
- $(".win-refresh").click(function(){
- window.location.reload();
- });
- $(".win-print").click(function(){
- window.print();
- });
- $(".win-close").click(function(){
- window.close();
- });
- $('.checkall').click(function(){
- var e=$(this);
- var name=e.attr("name");
- var checkfor=e.attr("checkfor");
- var type;
- if (checkfor!='' && checkfor!=null && checkfor!=undefined){
- type=e.closest('form').find("input[name='"+checkfor+"']");
- }else{
- type=e.closest('form').find("input[type='checkbox']");
- };
- if (name=="checkall"){
- $(type).each(function(index, element){
- element.checked=true;
- });
- e.attr("name","ok");
- }else{
- $(type).each(function(index, element){
- element.checked=false;
- });
- e.attr("name","checkall");
- }
- });
- $('.dropdown-toggle').click(function(){
- $(this).closest('.button-group, .drop').addClass("open");
- });
- $(document).bind("click",function(e){
- if($(e.target).closest(".button-group.open, .drop.open").length == 0){
- $(".button-group, .drop").removeClass("open");
- }
- });
- $checkplaceholder=function(){
- var input = document.createElement('input');
- return 'placeholder' in input;
- };
- if(!$checkplaceholder()){
- $("textarea[placeholder], input[placeholder]").each(function(index, element){
- var content=false;
- if($(this).val().length ===0 || $(this).val()==$(this).attr("placeholder")){content=true};
- if(content){
- $(element).val($(element).attr("placeholder"));
- $(element).css("color","rgb(169,169,169)");
- $(element).data("pintuerholder",$(element).css("color"));
- $(element).focus(function(){$hideplaceholder($(this));});
- $(element).blur(function(){$showplaceholder($(this));});
- }
- })
- };
- $showplaceholder=function(element){
- if( ($(element).val().length ===0 || $(element).val()==$(element).attr("placeholder")) && $(element).attr("type")!="password"){
- $(element).val($(element).attr("placeholder"));
- $(element).data("pintuerholder",$(element).css("color"));
- $(element).css("color","rgb(169,169,169)");
- }
- };
- var $hideplaceholder=function(element){
- if($(element).data("pintuerholder")){
- $(element).val("");
- $(element).css("color", $(element).data("pintuerholder"));
- $(element).removeData("pintuerholder");
- }
- };
- $('textarea, input, select').blur(function(){
- var e=$(this);
- if(e.attr("data-validate")){
- e.closest('.field').find(".input-help").remove();
- var $checkdata=e.attr("data-validate").split(',');
- var $checkvalue=e.val();
- var $checkstate=true;
- var $checktext="";
- if(e.attr("placeholder")==$checkvalue){$checkvalue="";}
- if($checkvalue!="" || e.attr("data-validate").indexOf("required")>=0){
- for(var i=0;i<$checkdata.length;i++){
- var $checktype=$checkdata[i].split(':');
- if(! $pintuercheck(e,$checktype[0],$checkvalue)){
- $checkstate=false;
- $checktext=$checktext+"
"+$checktype[1]+"";
- }
- }
- };
- if($checkstate){
- e.closest('.form-group').removeClass("check-error");
- e.parent().find(".input-help").remove();
- e.closest('.form-group').addClass("check-success");
- }else{
- e.closest('.form-group').removeClass("check-success");
- e.closest('.form-group').addClass("check-error");
- e.closest('.field').append('
');
- }
- }
- });
- $pintuercheck=function(element,type,value){
- $pintu=value.replace(/(^\s*)|(\s*$)/g, "");
- switch(type){
- case "required":return /[^(^\s*)|(\s*$)]/.test($pintu);break;
- case "chinese":return /^[\u0391-\uFFE5]+$/.test($pintu);break;
- case "number":return /^\d+$/.test($pintu);break;
- case "integer":return /^[-\+]?\d+$/.test($pintu);break;
- case "plusinteger":return /^[+]?\d+$/.test($pintu);break;
- case "double":return /^[-\+]?\d+(\.\d+)?$/.test($pintu);break;
- case "plusdouble":return /^[+]?\d+(\.\d+)?$/.test($pintu);break;
- case "english":return /^[A-Za-z]+$/.test($pintu);break;
- case "username":return /^[a-z]\w{3,}$/i.test($pintu);break;
- case "mobile":return /^((\(\d{3}\))|(\d{3}\-))?13[0-9]\d{8}?$|15[89]\d{8}?$|170\d{8}?$|147\d{8}?$/.test($pintu);break;
- case "phone":return /^((\(\d{2,3}\))|(\d{3}\-))?(\(0\d{2,3}\)|0\d{2,3}-)?[1-9]\d{6,7}(\-\d{1,4})?$/.test($pintu);break;
- case "tel":return /^((\(\d{3}\))|(\d{3}\-))?13[0-9]\d{8}?$|15[89]\d{8}?$|170\d{8}?$|147\d{8}?$/.test($pintu) || /^((\(\d{2,3}\))|(\d{3}\-))?(\(0\d{2,3}\)|0\d{2,3}-)?[1-9]\d{6,7}(\-\d{1,4})?$/.test($pintu);break;
- case "email":return /^[^@]+@[^@]+\.[^@]+$/.test($pintu);break;
- case "url":return /^http:\/\/[A-Za-z0-9]+\.[A-Za-z0-9]+[\/=\?%\-&_~`@[\]\':+!]*([^<>\"\"])*$/.test($pintu);break;
- case "ip":return /^[\d\.]{7,15}$/.test($pintu);break;
- case "qq":return /^[1-9]\d{4,10}$/.test($pintu);break;
- case "currency":return /^\d+(\.\d+)?$/.test($pintu);break;
- case "zip":return /^[1-9]\d{5}$/.test($pintu);break;
- case "radio":
- var radio=element.closest('form').find('input[name="'+element.attr("name")+'"]:checked').length;
- return eval(radio==1);
- break;
- default:
- var $test=type.split('#');
- if($test.length>1){
- switch($test[0]){
- case "compare":
- return eval(Number($pintu)+$test[1]);
- break;
- case "regexp":
- return new RegExp($test[1],"gi").test($pintu);
- break;
- case "length":
- var $length;
- if(element.attr("type")=="checkbox"){
- $length=element.closest('form').find('input[name="'+element.attr("name")+'"]:checked').length;
- }else{
- $length=$pintu.replace(/[\u4e00-\u9fa5]/g,"***").length;
- }
- return eval($length+$test[1]);
- break;
- case "ajax":
- var $getdata;
- var $url=$test[1]+$pintu;
- $.ajaxSetup({async:false});
- $.getJSON($url,function(data){
- //alert(data.getdata);
- $getdata=data.getdata;
- });
- if($getdata=="true"){return true;}
- break;
- case "repeat":
- return $pintu==jQuery('input[name="'+$test[1]+'"]').eq(0).val();
- break;
- default:return true;break;
- }
- break;
- }else{
- return true;
- }
- }
- };
- $('form').submit(function(){
- $(this).find('input[data-validate],textarea[data-validate],select[data-validate]').trigger("blur");
- $(this).find('input[placeholder],textarea[placeholder]').each(function(){$hideplaceholder($(this));});
- var numError = $(this).find('.check-error').length;
- if(numError){
- $(this).find('.check-error').first().find('input[data-validate],textarea[data-validate],select[data-validate]').first().focus().select();
- return false;
- }
- });
- $('.form-reset').click(function(){
- $(this).closest('form').find(".input-help").remove();
- $(this).closest('form').find('.form-submit').removeAttr('disabled');
- $(this).closest('form').find('.form-group').removeClass("check-error");
- $(this).closest('form').find('.form-group').removeClass("check-success");
- });
- $('.tab .tab-nav li').each(function(){
- var e=$(this);
- var trigger=e.closest('.tab').attr("data-toggle");
- if (trigger=="hover"){
- e.mouseover(function(){
- $showtabs(e);
- });
- e.click(function(){
- return false;
- });
- }else{
- e.click(function(){
- $showtabs(e);
- return false;
- });
- }
- });
- $showtabs=function(e){
- var detail=e.children("a").attr("href");
- e.closest('.tab .tab-nav').find("li").removeClass("active");
- e.closest('.tab').find(".tab-body .tab-panel").removeClass("active");
- e.addClass("active");
- $(detail).addClass("active");
- };
- $('.dialogs').each(function(){
- var e=$(this);
- var trigger=e.attr("data-toggle");
- if (trigger=="hover"){
- e.mouseover(function(){
- $showdialogs(e);
- });
- }else if(trigger=="click"){
- e.click(function(){
- $showdialogs(e);
- });
- }
- });
- $showdialogs=function(e){
- var trigger=e.attr("data-toggle");
- var getid=e.attr("data-target");
- var data=e.attr("data-url");
- var mask=e.attr("data-mask");
- var width=e.attr("data-width");
- var detail="";
- var masklayout=$('
');
- if(width==null){width="80%";}
-
- if (mask=="1"){
- $("body").append(masklayout);
- }
- detail='
';
- if(getid!=null){detail=detail+$(getid).html();}
- if(data!=null){detail=detail+$.ajax({url:data,async:false}).responseText;}
- //alert(detail);
- detail=detail+'
';
-
- var win=$(detail);
- win.find(".dialog").addClass("open");
- $("body").append(win);
- var x=parseInt($(window).width()-win.outerWidth())/2;
- var y=parseInt($(window).height()-win.outerHeight())/2;
- if (y<=10){y="10"}
- win.css({"left":x,"top":y});
- win.find(".dialog-close,.close").each(function(){
- $(this).click(function(){
- win.remove();
- $('.dialog-mask').remove();
- });
- });
- masklayout.click(function(){
- win.remove();
- $(this).remove();
- });
- };
- $('.tips').each(function(){
- var e=$(this);
- var title=e.attr("title");
- var trigger=e.attr("data-toggle");
- e.attr("title","");
- if (trigger=="" || trigger==null){trigger="hover";}
- if (trigger=="hover"){
- e.mouseover(function(){
- $showtips(e,title);
- });
- }else if(trigger=="click"){
- e.click(function(){
- $showtips(e,title);
- });
- }else if(trigger=="show"){
- e.ready(function(){
- $showtips(e,title);
- });
- }
- });
- $showtips=function(e,title){
- var trigger=e.attr("data-toggle");
- var place=e.attr("data-place");
- var width=e.attr("data-width");
- var css=e.attr("data-style");
- var image=e.attr("data-image");
- var content=e.attr("content");
- var getid=e.attr("data-target");
- var data=e.attr("data-url");
- var x=0;
- var y=0;
- var html="";
- var detail="";
-
- if(image!=null){detail=detail+'

';}
- if(content!=null){detail=detail+'
'+content+'
';}
- if(getid!=null){detail=detail+$(getid).html();}
- if(data!=null){detail=detail+$.ajax({url:data,async:false}).responseText;}
- if(title!=null && title!=""){
- if(detail!=null && detail!=""){detail='
'+title+'
'+detail;}else{detail='
'+title+'
';}
- }
- detail='
'+detail+'
';
- html=$(detail);
-
- $("body").append( html );
- if(width!=null){
- html.css("width",width);
- }
- if(place=="" || place==null){place="top";}
- if(place=="left"){
- x=e.offset().left - html.outerWidth()-5;
- y=e.offset().top - html.outerHeight()/2 + e.outerHeight()/2;
- }else if(place=="top"){
- x=e.offset().left - html.outerWidth()/2 + e.outerWidth()/2;
- y=e.offset().top - html.outerHeight()-5;
- }else if(place=="right"){
- x=e.offset().left + e.outerWidth()+5;
- y=e.offset().top - html.outerHeight()/2 + e.outerHeight()/2;
- }else if(place=="bottom"){
- x=e.offset().left - html.outerWidth()/2 + e.outerWidth()/2;
- y=e.offset().top + e.outerHeight()+5;
- }
- if (css!=""){html.addClass(css);}
- html.css({"left":x+"px","top":y+"px","position":"absolute"});
- if (trigger=="hover" || trigger=="click" || trigger==null){
- e.mouseout(function(){html.remove();e.attr("title",title)});
- }
- };
- $('.alert .close').each(function(){
- $(this).click(function(){
- $(this).closest('.alert').remove();
- });
- });
- $('.radio label').each(function(){
- var e=$(this);
- e.click(function(){
- e.closest('.radio').find("label").removeClass("active");
- e.addClass("active");
- });
- });
- $('.checkbox label').each(function(){
- var e=$(this);
- e.click(function(){
- if(e.find('input').is(':checked')){
- e.addClass("active");
- }else{
- e.removeClass("active");
- };
- });
- });
- $('.collapse .panel-head').each(function(){
- var e=$(this);
- e.click(function(){
- e.closest('.collapse').find(".panel").removeClass("active");
- e.closest('.panel').addClass("active");
- });
- });
- $('.icon-navicon').each(function(){
- var e=$(this);
- var target=e.attr("data-target");
- e.click(function(){
- $(target).toggleClass("nav-navicon");
- });
- });
- $('.banner').each(function(){
- var e=$(this);
- var pointer=e.attr("data-pointer");
- var interval=e.attr("data-interval");
- var style=e.attr("data-style");
- var items=e.attr("data-item");
- var items_s=e.attr("data-small");
- var items_m=e.attr("data-middle");
- var items_b=e.attr("data-big");
- var num=e.find(".carousel .item").length;
- var win=$(window).width();
- var i=1;
-
- if(interval==null){interval=5};
- if(items==null || items<1){items=1};
- if(items_s!=null && win>760){items=items_s};
- if(items_m!=null && win>1000){items=items_m};
- if(items_b!=null && win>1200){items=items_b};
-
- var itemWidth=Math.ceil(e.outerWidth()/items);
- var page=Math.ceil(num/items);
- e.find(".carousel .item").css("width",itemWidth+ "px");
- e.find(".carousel").css("width",itemWidth*num + "px");
-
- var carousel=function(){
- i++;
- if(i>page){i=1;}
- $showbanner(e,i,items,num);
- };
- var play=setInterval(carousel,interval*600);
-
- e.mouseover(function(){clearInterval(play);});
- e.mouseout(function(){play=setInterval(carousel,interval*600);});
-
- if(pointer!=0 && page>1){
- var point='
';
- for (var j=1;j';
- };
- point=point+'
';
- var pager=$(point);
- if(style!=null){pager.addClass(style);};
- e.append(pager);
- pager.css("left",e.outerWidth()*0.5 - pager.outerWidth()*0.5+"px");
- pager.find("li").click(function(){
- $showbanner(e,$(this).val(),items,num);
- });
- var lefter=$('');
- var righter=$('');
- if(style!=null){lefter.addClass(style);righter.addClass(style);};
- e.append(lefter);
- e.append(righter);
-
- lefter.click(function(){
- i--;
- if(i<1){i=page;}
- $showbanner(e,i,items,num);
- });
- righter.click(function(){
- i++;
- if(i>page){i=1;}
- $showbanner(e,i,items,num);
- });
- };
- });
- $showbanner=function(e,i,items,num){
- var after=0,leftx=0;
- leftx = - Math.ceil(e.outerWidth()/items)*(items)*(i-1);
- if(i*items > num){after=i*items-num;leftx= - Math.ceil(e.outerWidth()/items)*(num-items);};
- e.find(".carousel").stop(true, true).animate({"left":leftx+"px"},800);
- e.find(".pointer li").removeClass("active");
- e.find(".pointer li").eq(i-1).addClass("active");
- };
- $(".spy a").each(function(){
- var e=$(this);
- var t=e.closest(".spy");
- var target=t.attr("data-target");
- var top=t.attr("data-offset-spy");
- var thistarget="";
- var thistop="";
- if(top==null){top=0;};
- if(target==null){thistarget=$(window);}else{thistarget=$(target);};
-
- thistarget.bind("scroll",function(){
- if(target==null){
- thistop=$(e.attr("href")).offset().top - $(window).scrollTop() - parseInt(top);
- }else{
- thistop=$(e.attr("href")).offset().top - thistarget.offset().top - parseInt(top);
- };
-
- if(thistop<0){
- t.find('li').removeClass("active");
- e.parents('li').addClass("active");
- };
-
- });
- });
- $(".fixed").each(function(){
- var e=$(this);
- var style=e.attr("data-style");
- var top=e.attr("data-offset-fixed");
- if(top==null){top=e.offset().top;}else{top=e.offset().top - parseInt(top);};
- if(style==null){style="fixed-top";};
-
- $(window).bind("scroll",function(){
- var thistop=top - $(window).scrollTop();
- if(style=="fixed-top" && thistop<0){
- e.addClass("fixed-top");
- }else{
- e.removeClass("fixed-top");
- };
-
- var thisbottom=top - $(window).scrollTop()-$(window).height();
- if(style=="fixed-bottom" && thisbottom>0){
- e.addClass("fixed-bottom");
- }else{
- e.removeClass("fixed-bottom");
- };
- });
-
- });
-
-})
\ No newline at end of file
diff --git a/backend/pom.xml b/backend/pom.xml
new file mode 100644
index 0000000..328db15
--- /dev/null
+++ b/backend/pom.xml
@@ -0,0 +1,106 @@
+
+
+ 4.0.0
+
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 2.7.18
+
+
+
+ cn.forgeeks
+ domt
+ 1.0.0
+ domt
+ Dormitory Management System
+
+
+ 17
+ 2.3.2
+ 5.2.5
+ 1.8.0
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-validation
+
+
+
+
+ org.mybatis.spring.boot
+ mybatis-spring-boot-starter
+ ${mybatis-spring-boot.version}
+
+
+
+
+ com.mysql
+ mysql-connector-j
+ runtime
+
+
+
+
+ org.projectlombok
+ lombok
+ true
+
+
+
+
+ org.apache.poi
+ poi-ooxml
+ ${poi.version}
+
+
+
+
+ org.springdoc
+ springdoc-openapi-ui
+ ${springdoc.version}
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+
+
+ com.h2database
+ h2
+ test
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+ org.projectlombok
+ lombok
+
+
+
+
+
+
+
diff --git a/backend/src/main/java/cn/forgeeks/domt/DomtApplication.java b/backend/src/main/java/cn/forgeeks/domt/DomtApplication.java
new file mode 100644
index 0000000..a889148
--- /dev/null
+++ b/backend/src/main/java/cn/forgeeks/domt/DomtApplication.java
@@ -0,0 +1,14 @@
+package cn.forgeeks.domt;
+
+import org.mybatis.spring.annotation.MapperScan;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+@MapperScan("cn.forgeeks.domt.mapper")
+public class DomtApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(DomtApplication.class, args);
+ }
+}
diff --git a/backend/src/main/java/cn/forgeeks/domt/config/WebConfig.java b/backend/src/main/java/cn/forgeeks/domt/config/WebConfig.java
new file mode 100644
index 0000000..308d619
--- /dev/null
+++ b/backend/src/main/java/cn/forgeeks/domt/config/WebConfig.java
@@ -0,0 +1,32 @@
+package cn.forgeeks.domt.config;
+
+import cn.forgeeks.domt.interceptor.AuthInterceptor;
+import lombok.RequiredArgsConstructor;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.config.annotation.CorsRegistry;
+import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+@Configuration
+@RequiredArgsConstructor
+public class WebConfig implements WebMvcConfigurer {
+
+ private final AuthInterceptor authInterceptor;
+
+ @Override
+ public void addInterceptors(InterceptorRegistry registry) {
+ registry.addInterceptor(authInterceptor)
+ .addPathPatterns("/api/**")
+ .excludePathPatterns("/api/auth/login");
+ }
+
+ @Override
+ public void addCorsMappings(CorsRegistry registry) {
+ registry.addMapping("/**")
+ .allowedOrigins("http://localhost:5173")
+ .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
+ .allowedHeaders("*")
+ .allowCredentials(true)
+ .maxAge(3600);
+ }
+}
diff --git a/backend/src/main/java/cn/forgeeks/domt/controller/AnnouncementController.java b/backend/src/main/java/cn/forgeeks/domt/controller/AnnouncementController.java
new file mode 100644
index 0000000..1ab5d5c
--- /dev/null
+++ b/backend/src/main/java/cn/forgeeks/domt/controller/AnnouncementController.java
@@ -0,0 +1,59 @@
+package cn.forgeeks.domt.controller;
+
+import cn.forgeeks.domt.dto.PageResult;
+import cn.forgeeks.domt.dto.Result;
+import cn.forgeeks.domt.entity.Announcement;
+import cn.forgeeks.domt.service.AnnouncementService;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+@RestController
+@RequestMapping("/api/announcements")
+public class AnnouncementController {
+
+ private final AnnouncementService announcementService;
+
+ public AnnouncementController(AnnouncementService announcementService) {
+ this.announcementService = announcementService;
+ }
+
+ @GetMapping
+ public Result
> list(
+ @RequestParam(defaultValue = "1") int pageNo,
+ @RequestParam(defaultValue = "10") int pageSize,
+ @RequestParam(required = false) String title) {
+ PageResult page = announcementService.findPage(pageNo, pageSize, title);
+ return Result.success(page);
+ }
+
+ @GetMapping("/{id}")
+ public Result getById(@PathVariable String id) {
+ return Result.success(announcementService.getById(id));
+ }
+
+ @PostMapping
+ public Result create(@RequestBody Announcement announcement) {
+ announcementService.create(announcement);
+ return Result.success();
+ }
+
+ @PutMapping("/{id}")
+ public Result update(@PathVariable String id, @RequestBody Announcement announcement) {
+ announcement.setAnnouncementId(id);
+ announcementService.update(announcement);
+ return Result.success();
+ }
+
+ @DeleteMapping("/{id}")
+ public Result deleteById(@PathVariable String id) {
+ announcementService.deleteById(id);
+ return Result.success();
+ }
+
+ @DeleteMapping("/batch")
+ public Result deleteBatch(@RequestBody List ids) {
+ announcementService.deleteBatch(ids);
+ return Result.success();
+ }
+}
diff --git a/backend/src/main/java/cn/forgeeks/domt/controller/ApartmentController.java b/backend/src/main/java/cn/forgeeks/domt/controller/ApartmentController.java
new file mode 100644
index 0000000..ac888b4
--- /dev/null
+++ b/backend/src/main/java/cn/forgeeks/domt/controller/ApartmentController.java
@@ -0,0 +1,70 @@
+package cn.forgeeks.domt.controller;
+
+import cn.forgeeks.domt.dto.PageResult;
+import cn.forgeeks.domt.dto.Result;
+import cn.forgeeks.domt.entity.Apartment;
+import cn.forgeeks.domt.service.ApartmentService;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+@RestController
+@RequestMapping("/api/apartments")
+public class ApartmentController {
+
+ private final ApartmentService apartmentService;
+
+ public ApartmentController(ApartmentService apartmentService) {
+ this.apartmentService = apartmentService;
+ }
+
+ @GetMapping
+ public Result> list(
+ @RequestParam(defaultValue = "1") int pageNo,
+ @RequestParam(defaultValue = "10") int pageSize,
+ @RequestParam(required = false) String apartmentName,
+ @RequestParam(required = false) String sex) {
+ PageResult page = apartmentService.findPage(pageNo, pageSize, apartmentName, sex);
+ return Result.success(page);
+ }
+
+ @GetMapping("/{id}")
+ public Result getById(@PathVariable String id) {
+ return Result.success(apartmentService.getById(id));
+ }
+
+ @GetMapping("/all")
+ public Result> getAll() {
+ return Result.success(apartmentService.findAll());
+ }
+
+ @GetMapping("/by-sex/{sex}")
+ public Result> getBySex(@PathVariable String sex) {
+ return Result.success(apartmentService.findBySex(sex));
+ }
+
+ @PostMapping
+ public Result create(@RequestBody Apartment apartment) {
+ apartmentService.create(apartment);
+ return Result.success();
+ }
+
+ @PutMapping("/{id}")
+ public Result update(@PathVariable String id, @RequestBody Apartment apartment) {
+ apartment.setApartmentId(id);
+ apartmentService.update(apartment);
+ return Result.success();
+ }
+
+ @DeleteMapping("/{id}")
+ public Result deleteById(@PathVariable String id) {
+ apartmentService.deleteById(id);
+ return Result.success();
+ }
+
+ @DeleteMapping("/batch")
+ public Result deleteBatch(@RequestBody List ids) {
+ apartmentService.deleteBatch(ids);
+ return Result.success();
+ }
+}
diff --git a/backend/src/main/java/cn/forgeeks/domt/controller/AuthController.java b/backend/src/main/java/cn/forgeeks/domt/controller/AuthController.java
new file mode 100644
index 0000000..29cf606
--- /dev/null
+++ b/backend/src/main/java/cn/forgeeks/domt/controller/AuthController.java
@@ -0,0 +1,44 @@
+package cn.forgeeks.domt.controller;
+
+import cn.forgeeks.domt.dto.LoginRequest;
+import cn.forgeeks.domt.dto.LoginResponse;
+import cn.forgeeks.domt.dto.Result;
+import cn.forgeeks.domt.service.AuthService;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpSession;
+import javax.validation.Valid;
+
+@RestController
+@RequestMapping("/api/auth")
+public class AuthController {
+
+ private final AuthService authService;
+
+ public AuthController(AuthService authService) {
+ this.authService = authService;
+ }
+
+ @PostMapping("/login")
+ public Result login(@Valid @RequestBody LoginRequest loginRequest,
+ HttpSession session) {
+ LoginResponse response = authService.login(loginRequest.getUsername(), loginRequest.getPassword());
+ session.setAttribute("loginUser", response);
+ return Result.success(response);
+ }
+
+ @PostMapping("/logout")
+ public Result logout(HttpSession session) {
+ session.invalidate();
+ return Result.success();
+ }
+
+ @GetMapping("/current")
+ public Result current(HttpSession session) {
+ LoginResponse loginUser = (LoginResponse) session.getAttribute("loginUser");
+ if (loginUser == null) {
+ return Result.error(401, "未登录");
+ }
+ return Result.success(loginUser);
+ }
+}
diff --git a/backend/src/main/java/cn/forgeeks/domt/controller/BedroomController.java b/backend/src/main/java/cn/forgeeks/domt/controller/BedroomController.java
new file mode 100644
index 0000000..747a49a
--- /dev/null
+++ b/backend/src/main/java/cn/forgeeks/domt/controller/BedroomController.java
@@ -0,0 +1,81 @@
+package cn.forgeeks.domt.controller;
+
+import cn.forgeeks.domt.dto.PageResult;
+import cn.forgeeks.domt.dto.Result;
+import cn.forgeeks.domt.entity.Bedroom;
+import cn.forgeeks.domt.service.BedroomService;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@RestController
+@RequestMapping("/api/bedrooms")
+public class BedroomController {
+
+ private final BedroomService bedroomService;
+
+ public BedroomController(BedroomService bedroomService) {
+ this.bedroomService = bedroomService;
+ }
+
+ @GetMapping
+ public Result> list(
+ @RequestParam(defaultValue = "1") int pageNo,
+ @RequestParam(defaultValue = "10") int pageSize,
+ @RequestParam(required = false) String bedroomName,
+ @RequestParam(required = false) String apartmentId,
+ @RequestParam(required = false) String status) {
+ PageResult page = bedroomService.findPage(pageNo, pageSize, bedroomName, apartmentId, status);
+ return Result.success(page);
+ }
+
+ @GetMapping("/{id}")
+ public Result getById(@PathVariable String id) {
+ return Result.success(bedroomService.getById(id));
+ }
+
+ @GetMapping("/by-apartment/{apartmentId}")
+ public Result> getByApartmentId(@PathVariable String apartmentId) {
+ return Result.success(bedroomService.findByApartmentId(apartmentId));
+ }
+
+ @GetMapping("/available/{apartmentId}")
+ public Result> getAvailableByApartmentId(@PathVariable String apartmentId) {
+ return Result.success(bedroomService.findAvailableByApartmentId(apartmentId));
+ }
+
+ @GetMapping("/stats/{apartmentId}")
+ public Result