個(gè)人資料
(一)個(gè)人資料(持久層)
1.規(guī)劃sql
根據(jù)用戶id修改信息的SQL語句
update t_user set python=?,email=?,gender=?,modified_user=?,modified_time=? where uid=?
根據(jù)用戶id查詢的sql語句
select * from t_user where uid=?
2.接口與抽象方法
更新用戶的信息方法的定義
//根據(jù)id修改
Integer updateInfoByUid(User user);
在UserMapper.xml文件中進(jìn)行映射編寫
<update id="updateInfoByUid" >
update t_user set
<!--if是條件判斷標(biāo)簽,屬性test接受的是一個(gè)返回值為boolean類型的條件,
如果test條件的結(jié)果為true則執(zhí)行if標(biāo)簽內(nèi)部的語句,注意逗號也要在標(biāo)簽內(nèi)-->
<if test="phone!=null">phone=#{phone},</if>
<if test="email!=null"> email=#{email},</if>
<if test="gender!=null">gender=#{gender},</if>
modified_user=#{modifiedUser},
modified_time=#{modifiedTime}
where
uid=#{uid}
</update>
(二)個(gè)人資料(業(yè)務(wù)層)
設(shè)計(jì)兩個(gè)功能:
1.當(dāng)打開頁面時(shí)顯示當(dāng)前登錄的用戶的信息
2.點(diǎn)擊修改按鈕時(shí)更新用戶的信息
1.異常規(guī)劃
點(diǎn)擊個(gè)人資料頁面時(shí)可能找不到用戶的數(shù)據(jù)
點(diǎn)擊修改按鈕時(shí)可能找不到用戶數(shù)據(jù),也可能修改時(shí)出現(xiàn)未知錯(cuò)誤
2.設(shè)計(jì)接口和抽象方法及實(shí)現(xiàn)
業(yè)務(wù)層有兩個(gè)功能模塊,對應(yīng)的是兩個(gè)抽象方法的設(shè)計(jì),并且這兩個(gè)功能都涉及到用戶是否存在的查詢操作,所以需要在業(yè)務(wù)層設(shè)計(jì)根據(jù)用戶uid查詢數(shù)據(jù)的方法(持久層已經(jīng)設(shè)計(jì)過該方法,但是沒有在業(yè)務(wù)層實(shí)現(xiàn)該方法的調(diào)用)
//修改個(gè)人資料 uid通過控制層在session中獲取然后傳遞給業(yè)務(wù)層,并在業(yè)務(wù)層封裝到User對象中
void changeInfo(Integer uid,String username,User user);
//根據(jù)id查詢
User getByUid(Integer uid);
在實(shí)現(xiàn)類中實(shí)現(xiàn)當(dāng)前的抽象方法
@Override
public void changeInfo(Integer uid, String username, User user) {
//查詢用戶是否存在
User user1=userMapper.findUid(uid);
if (user1==null || user1.getIsDelete()==1){
throw new UsernameNotFoundException("用戶不存在");
}
//User對象中的數(shù)據(jù)只有phone,email,gender,username,因?yàn)閟pringboot進(jìn)行依賴
//注入的時(shí)候只注入表單中數(shù)據(jù)的值,所以需要手動(dòng)將uid封裝到user中
user.setUid(uid);
user.setUsername(username);
user.setModifiedUser(username);
user.setModifiedTime(new Date());
Integer rows= userMapper.updateInfoByUid(user);
if (rows!=1){
throw new UpdateException("修改時(shí)出現(xiàn)未知異常");
}
}
@Override
public User getByUid(Integer uid) {
User user1=userMapper.findUid(uid);
if (user1==null || user1.getIsDelete()==1){
throw new UsernameNotFoundException("用戶不存在");
}
User user=new User();
user.setUsername(user1.getUsername());
// user.setModifiedUser(user1.getModifiedUser());
// user.setModifiedTime( user1.getModifiedTime());
user.setEmail( user1.getEmail());
user.setPhone(user1.getPhone());
user.setGender(user1.getGender());
return user;
}
(三)個(gè)人資料(控制層)
1.設(shè)計(jì)請求
1.設(shè)計(jì)一打開頁面就發(fā)送當(dāng)前用戶數(shù)據(jù)的查詢:
請求路徑: /users/get_by_uid
請求方式:GET
請求參數(shù):HttpSession session(用于獲取uid)
響應(yīng)結(jié)果:JsonResult< User>
2.點(diǎn)擊修改按鈕發(fā)送用戶的數(shù)據(jù)修改操作
請求路徑:users/change_info
請求方式:POST
請求參數(shù):User user,HttpSession session(用于獲取uid)
響應(yīng)結(jié)果:JsonResult< Void>
2.處理請求
@GetMapping("/get_by_uid")
public JsonResult<User> getbyUid(HttpSession session){
User user=userService.getByUid(getuidfromsession(session));
return new JsonResult<>(ok,user);
}
@PostMapping("/change_info")
public JsonResult<Void> changeinfo(User user,HttpSession session){
Integer getuidfromsession = getuidfromsession(session);
String getusernamesession = getusernamesession(session);
userService.changeInfo(getuidfromsession,getusernamesession,user);
return new JsonResult<>(ok);
}
(四)個(gè)人資料(前端頁面)
在打開userdata.html(個(gè)人資料)頁面自動(dòng)發(fā)送ajax請求(get_by_uid),查詢到的數(shù)據(jù)填充到這個(gè)頁面
$(document).ready(function () {
$.ajax({
url:"/users/get_by_uid",
type:"GET",
data:$("#form-change-info").serialize(),
dataType:"JSON",
//2.發(fā)送ajax()的異步請求來完成用戶的注冊功能
success:function (json) {
if (json.state==200){
$("#username").val(json.data.username);
$("#phone").val(json.data.phone);
$("#email").val(json.data.email);
var radio=json.data.gender==0 ?
$("#gender-female") : $("#gender-male");
//prop()表示給某個(gè)元素添加屬性及屬性值
radio.prop("checked","checked");
}else{
alert("用戶數(shù)據(jù)不存在");
}
},
error:function (xhr) {
alert("查詢用戶信息產(chǎn)生未知異常"+xhr.message);
}
});
});
在檢測到用戶點(diǎn)擊了修改按鈕后發(fā)送一個(gè)ajax請求(change_info)
(該ajax函數(shù)需要和上一個(gè)ajax同級)
//1.監(jiān)聽按鈕是否被點(diǎn)擊
$("#btn-change-info").click(function () {
$.ajax({
url:"/users/change_info",
type:"POST",
data:$("#form-change-info").serialize(),
dataType:"JSON",
//2.發(fā)送ajax()的異步請求來完成用戶的注冊功能
success:function (json) {
if (json.state==200){
alert("修改成功");
//跳轉(zhuǎn)系統(tǒng)主頁index。html
//相對路徑
location.href="userdata.html";
}else{
alert("修改失敗失敗");
}
},
error:function (xhr) {
alert("修改產(chǎn)生未知異常"+xhr.message);
}
});
});
上傳頭像
(一)上傳頭像(持久層)
1.規(guī)劃sql
update t_user set avatar=?,modified_user=?,modified_time=? where uid=?
2.接口設(shè)計(jì)和實(shí)現(xiàn)方法
在UserMapper接口中定義一個(gè)抽象方法用于修改用戶的頭像
//修改用戶頭像
Integer updateAvatarByUid(@Param("uid") Integer uid,
@Param("avatar") String avatar,
@Param("modifiedUser") String modifiedUser,
@Param("modifiedTime") Date modifiedTime);
在UserMapper.xml文件中進(jìn)行映射編寫
<!-- 上傳頭像-->
<update id="updateAvatarByUid">
update t_user set
avatar=#{avatar},
modified_user=#{modifiedUser},
modified_time=#{modifiedTime}
where
uid=#{uid}
</update>
(二)上傳頭像(業(yè)務(wù)層)
1.規(guī)劃異常
用戶數(shù)據(jù)不存在,找不到對應(yīng)的用戶數(shù)據(jù)
更新的時(shí)候,出現(xiàn)未知異常
(前面已經(jīng)寫過)
2.設(shè)計(jì)接口和抽象方法及實(shí)現(xiàn)
uid,avatar,modifiedUser,modifiedTime,其中modifiedTime是在方法中創(chuàng)建的,uid和modifiedUser從session中獲取,但是session對象是在控制層的并不會(huì)出現(xiàn)在業(yè)務(wù)層,所以業(yè)務(wù)層要保留這兩個(gè)參數(shù),以便控制層可以傳遞過來
//修改頭像
void changeAvatar(Integer uid,String avatar,String username);
編寫業(yè)務(wù)層的更新用戶頭像的方法
//修改頭像
@Override
public void changeAvatar(Integer uid, String avatar, String username) {
User user1 = userMapper.findUid(uid);
if (user1==null || user1.getIsDelete()==1){
throw new UsernameNotFoundException("用戶不存在");
}
Integer rows= userMapper.updateAvatarByUid(user1.getUid(),avatar,username,new Date());
if (rows!=1){
throw new UpdateException("上傳時(shí)出現(xiàn)未知異常");
}
}
(三)上傳頭像(控制層)
1.規(guī)劃異常
上傳文件時(shí)的異常都是文件異常,所以可以先創(chuàng)建一個(gè)文件異常類的基類FileUploadException并使其繼承RuntimeException
FileEmptyException:文件為空的異常(沒有選擇上傳的文件就提交了表單,或選擇的文件是0字節(jié)的空文件)
FileSizeException:文件大小超出限制
FileTypeException:文件類型異常(上傳的文件類型超出了限制)
FileUploadIOException:文件讀寫異常
FileStateException:文件狀態(tài)異常(上穿文件時(shí)該文件正在打開狀態(tài))
2.處理異常
在基類BaseController中進(jìn)行編寫和統(tǒng)一處理
else if (e instanceof FileEmptyException){
result.setState(6000);
}else if (e instanceof FileSizeException) {
result.setState(6001);
} else if (e instanceof FileTypeException) {
result.setState(6002);
} else if (e instanceof FileStateException) {
result.setState(6003);
} else if (e instanceof FileUploadIOException) {
result.setState(6004);
}
異常統(tǒng)一處理方法的修飾符@ExceptionHandler(ServiceException.class)表明我們現(xiàn)在創(chuàng)建的FileUploadException異常類不會(huì)被攔截到該方法中,點(diǎn)進(jìn)@ExceptionHandler注解可以發(fā)現(xiàn)傳參可以傳數(shù)組類型,所以可以將異常統(tǒng)一處理方法上的注解改為:
@ExceptionHandler({ServiceException.class,FileUploadException.class})
3.設(shè)計(jì)請求
請求路徑:/users/change_avatar
請求方式:POST(GET請求提交數(shù)據(jù)只有2KB左右)
請求參數(shù):HttpSession session(獲取uid和username),MultipartFile file
響應(yīng)結(jié)果:JsonResult< String>(不能是JsonResult< Void>)
4.處理請求
@RequestMapping("change_avatar")
public JsonResult<String> changeAvatar(HttpSession session,
MultipartFile file) {
/**
* 1.參數(shù)名為什么必須用file:在upload.html頁面的147行<input type=
* "file" name="file">中的name="file",所以必須有一個(gè)方法的參數(shù)名
* 為file用于接收前端傳遞的該文件.如果想要參數(shù)名和前端的name不一
* 樣:@RequestParam("file")MultipartFile ffff:把表單中name=
* "file"的控件值傳遞到變量ffff上
* 2.參數(shù)類型為什么必須是MultipartFile:這是springmvc中封裝的一個(gè)
* 包裝接口,如果類型是MultipartFile并且參數(shù)名和前端上傳文件的name
* 相同,則會(huì)自動(dòng)把整體的數(shù)據(jù)包傳遞給file
*/
//判斷文件是否為null
if (file.isEmpty()) {
throw new FileEmptyException("文件為空");
}
if (file.getSize()>AVATAR_MAX_SIZE) {
throw new FileSizeException("文件超出限制");
}
//判斷文件的類型是否是我們規(guī)定的后綴類型
String contentType = file.getContentType();
//如果集合包含某個(gè)元素則返回值為true
if (!AVATAR_TYPE.contains(contentType)) {
throw new FileTypeException("文件類型不支持");
}
//上傳的文件路徑:.../upload/文件名.png
/**
* session.getServletContext()獲取當(dāng)前Web應(yīng)用程序的上下文
* 對象(每次啟動(dòng)tomcat都會(huì)創(chuàng)建一個(gè)新的上下文對象)
* getRealPath("/upload")的/代表當(dāng)前web應(yīng)用程序的根目錄,通過該相
* 對路徑獲取絕對路徑,返回一個(gè)路徑字符串,如果不能進(jìn)行映射返回null,單
* 斜杠可要可不要
*/
String parent =
session.getServletContext().getRealPath("/upload");
System.out.println(parent);//調(diào)試用
//File對象指向這個(gè)路徑,通過判斷File是否存在得到該路徑是否存在
File dir = new File(parent);
if (!dir.exists()) {//檢測目錄是否存在
dir.mkdirs();//創(chuàng)建當(dāng)前目錄
}
//獲取這個(gè)文件名稱(文件名+后綴,如avatar01.png,不包含父目錄結(jié)構(gòu))用UUID
// 工具生成一個(gè)新的字符串作為文件名(好處:避免了因文件名重復(fù)發(fā)生的覆蓋)
String originalFilename = file.getOriginalFilename();
System.out.println("OriginalFilename="+originalFilename);
int index = originalFilename.lastIndexOf(".");
String suffix = originalFilename.substring(index);
//filename形如SAFS1-56JHIOHI-HIUGHUI-5565TYRF.png
String filename =
UUID.randomUUID().toString().toUpperCase()+suffix;
//在dir目錄下創(chuàng)建filename文件(此時(shí)是空文件)
File dest = new File(dir, filename);
//java可以把一個(gè)文件的數(shù)據(jù)直接寫到同類型的文件中,這里將參數(shù)file中的數(shù)據(jù)寫入到空文件dest中
try {
file.transferTo(dest);//transferTo是一個(gè)封裝的方法,用來將file文件中的數(shù)據(jù)寫入到dest文件
/**
* 先捕獲FileStateException再捕獲IOException是
* 因?yàn)楹笳甙罢?如果先捕獲IOException那么
* FileStateException就永遠(yuǎn)不可能會(huì)被捕獲
*/
} catch (FileStateException e) {
throw new FileStateException("文件狀態(tài)異常");
} catch (IOException e) {
//這里不用打印e,而是用自己寫的FileUploadIOException類并
// 拋出文件讀寫異常
throw new FileUploadIOException("文件讀寫異常");
}
Integer uid = getUidFromSession(session);
String username = getUsernameFromSession(session);
String avatar = "/upload/"+filename;
userService.changeAvatar(uid,avatar,username);
//返回用戶頭像的路徑給前端頁面,將來用于頭像展示使用
return new JsonResult<>(OK,avatar);
}
(四)上傳頭像(前端頁面)
1.前端頁面代碼
在upload.html的上傳頭像的表單加上三個(gè)屬性:
action=“/users/change_avatar”
method=“post”(get請求提交數(shù)據(jù)只有2KB左右)
enctype=“multipart/form-data”(如果直接使用表單進(jìn)行文件的上傳,需要給表單加該屬性,這樣不會(huì)將目標(biāo)文件的數(shù)據(jù)結(jié)構(gòu)做修改后再上傳,這不同于字符串,字符串隨意切割修改也能拼在一起,但文件不行)
2.前端頁面優(yōu)化
springmvc默認(rèn)為1MB文件可以進(jìn)行上傳,如果超過則會(huì)報(bào)代碼錯(cuò)誤,自己在控制層設(shè)置的public static final int AVATAR_MAX_SIZE = 1010241024;需要在不超過原有大小的情況下才會(huì)起作用,所以要手動(dòng)修改springmvc默認(rèn)上傳文件的大小
方式1:直接在配置文件application.properties中進(jìn)行配置:
spring.servlet.multipart.max-file-size=10MB(表示上傳的文件最大是多大)
spring.servlet.multipart.max-request-size=15MB(整個(gè)文件是放在了request中發(fā)送給服務(wù)器的,請求當(dāng)中還會(huì)有消息頭等其他攜帶的信息,這里設(shè)置請求最大為15MB)
方式2:采用java代碼的形式來設(shè)置文件的上傳大小的限制:
1.該代碼必須在主類中進(jìn)行配置,因?yàn)橹黝愂亲钤缂虞d的,而配置文件必須是最早加載的
2.在主類中定義一個(gè)方法,方法名無所謂,但方法需要用@bean修飾,表示該方法返回值是一個(gè)bean對象,并且該bean對象被bean修飾,也就是這個(gè)方法返回了一個(gè)對象,然后把該對象交給bean管理,類似spring中的bean標(biāo)簽,含義是一樣的,只是這里改為了注解
3.用@Configuration修飾主類使@bean注解生效,但其實(shí)@SpringBootApplication是@SpringBootConfiguration,@EnableAutoConfiguration,@ComponentScan三個(gè)注解的合并,所以可以不需要@Configuration
4.方法返回值是MultipartConfigElement類型,表示所要配置的目標(biāo)的元素
@Bean
public MultipartConfigElement getMultipartConfigElement() {
//1.創(chuàng)建一個(gè)配置的工廠類對象
MultipartConfigFactory factory = new MultipartConfigFactory();
//2.設(shè)置需要?jiǎng)?chuàng)建的對象的相關(guān)信息
factory.setMaxFileSize(DataSize.of(10, DataUnit.MEGABYTES));
factory.setMaxRequestSize(DataSize.of(15,DataUnit.MEGABYTES));
//3.通過工廠類創(chuàng)建MultipartConfigElement對象
return factory.createMultipartConfig();
}
3.頭像回顯
在頁面中通過ajax請求來提交文件,提交完成后返回了json串,解析出json串中的data數(shù)據(jù)設(shè)置到img標(biāo)簽的src屬性上
1.刪掉在upload.html的上傳頭像的表單中加的三個(gè)屬性:action=“/users/change_avatar”,method=“post”,enctype=“multipart/form-data”.加上id屬性:id=“form-change-avatar”
2.把153行的input標(biāo)簽里面的type="submit"改為type=“button”(因?yàn)閟ubmit按鈕不能添加事件,所以要改為普通的按鈕)并加上屬性id=“btn-change-avatar”
1.serialize():可以將表單數(shù)據(jù)自動(dòng)拼接成key=value的結(jié)構(gòu)提交給服務(wù)器,一般提交的是普通的控件類型中的數(shù)據(jù)(type=text/password/radio/checkbox等等)
2.FormData類:將表單中數(shù)據(jù)保持原有的結(jié)構(gòu)進(jìn)行數(shù)據(jù)提交.文件類型的數(shù)據(jù)可以使用FormData對象進(jìn)行存儲(chǔ)
使用方法:new FormData($(“form”)[0]);
這行代碼的含義是將id="form"的表單的第一個(gè)元素的整體值作為創(chuàng)建FormData對象的數(shù)據(jù)
3.雖然我們把文件的數(shù)據(jù)保護(hù)下來了,但是ajax默認(rèn)處理數(shù)據(jù)時(shí)按照字符串的形式進(jìn)行處理,以及默認(rèn)會(huì)采用字符串的形式進(jìn)行數(shù)據(jù)提交.手動(dòng)關(guān)閉這兩個(gè)功能:
processData: false,//處理數(shù)據(jù)的形式,關(guān)閉處理數(shù)據(jù)
contentType: false,//提交數(shù)據(jù)的形式,關(guān)閉默認(rèn)提交數(shù)據(jù)的形式
提交表單的代碼
<script>
$("#btn-change-avatar").click(function () {
$.ajax({
url: "/users/change_avatar",
type: "POST",
data: new FormData($("#form-change-avatar")[0]),
processData: false,//處理數(shù)據(jù)的形式,關(guān)閉處理數(shù)據(jù)
contentType: false,//提交數(shù)據(jù)的形式,關(guān)閉默認(rèn)提交數(shù)據(jù)的形式
dataType: "JSON",
success: function (json) {
if (json.state == 200) {
alert("頭像修改成功")
//將服務(wù)器端返回的頭像地址設(shè)置到img標(biāo)簽的src屬性上
//attr(屬性,屬性值)用來給某個(gè)屬性設(shè)值
$("#img-avatar").attr("src",json.data);
} else {
alert("頭像修改失敗")
}
},
error: function (xhr) {
alert("修改頭像時(shí)產(chǎn)生未知的異常!"+xhr.message);
}
});
});
</script>
4.登錄后顯示頭像
將頭像上傳后會(huì)顯示頭像,但是關(guān)閉瀏覽器后再進(jìn)入個(gè)人頭像頁面就不會(huì)顯示頭像了,因?yàn)橹挥悬c(diǎn)擊"上傳"才能發(fā)送ajax請求并顯示頭像.
可以在每次用戶登錄成功后將avatar保存在cookie中,登錄的業(yè)務(wù)層返回給控制層user對象,該對象包含uid,username,avatar.所以要在登錄頁面login.html中將服務(wù)器返回的頭像路徑設(shè)置到cookie中,然后每次檢測到用戶打開上傳頭像頁面,在這個(gè)頁面中通過ready()方法來自動(dòng)讀取cookie中頭像路徑并設(shè)到src屬性上。
1.需要在login.html頁面頭部導(dǎo)入cookie.js文件
<script src="../bootstrap3/js/jquery.cookie.js" type="text/javascript" charset="utf-8"></script>
2.調(diào)用cookie方法保存路徑
$.cookie(key,value,time);//time單位:天
在ajax請求原有的代碼上加$.cookie(“avatar”,json.data.avatar,{expires: 7});
success: function (json) {
if (json.state == 200) {
location.href = "index.html";
$.cookie("avatar",json.data.avatar,{expires: 7});
} else {
alert("登錄失敗")
}
},
3.需要在upload.html獲取cookie中的值,所以要在頁面頭部導(dǎo)入cookie.js文件
<script src="../bootstrap3/js/jquery.cookie.js" type="text/javascript" charset="utf-8"></script>
4.在upload.html的script標(biāo)簽中加ready()自動(dòng)讀取cookie數(shù)據(jù)
$(document).ready(function(){
var avatar = $.cookie("avatar");
console.log(avatar);//調(diào)試用
$("#img-avatar").attr("src",avatar);
})
5.顯示最新頭像
上傳頭像后不重新登錄而是瀏覽其他頁面,然后再進(jìn)入個(gè)人頭像頁面時(shí)展示的頭像是上次上傳的,因?yàn)榇藭r(shí)cookie中的值是上次上傳的頭像的路徑,所以需要上傳頭像后使用同名覆蓋更改cookie中路徑
在ajax函數(shù)的success屬性值的if語句加:文章來源:http://www.zghlxwxcb.cn/news/detail-439924.html
$.cookie("avatar",json.data,{expires: 7});
后記
????????美好的一天,到此結(jié)束,下次繼續(xù)努力!欲知后續(xù),請看下回分解,寫作不易,感謝大家的支持??! ??????文章來源地址http://www.zghlxwxcb.cn/news/detail-439924.html
到了這里,關(guān)于【五一創(chuàng)作】基于springboot框架的電腦商城項(xiàng)目(三)的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!