当前位置: 首页 > news >正文

网站优化的内容网页设计与制作课程介绍

网站优化的内容,网页设计与制作课程介绍,2019网站怎么做,保健食品东莞网站建设文章目录项目介绍#xff08;开发背景#xff09;数据库设计主要使用到的技术点前端后端自定义统一返回对象自定义拦截器加盐加密操作分页功能session持久化自定义头像的存储和获取项目编写过程中遇到的困难点困难点一#xff08;小#xff09;困难点二#xff08;小… 文章目录项目介绍开发背景数据库设计主要使用到的技术点前端后端自定义统一返回对象自定义拦截器加盐加密操作分页功能session持久化自定义头像的存储和获取项目编写过程中遇到的困难点困难点一小困难点二小困难点三大上传部署总结项目介绍开发背景 对于一个程序员来说定期整理总结并写博客是不可或缺的步骤不管是对近期新掌握的技术或者是遇到bug解决bug过程的记录等都是非常有必要的。         目前的博客网站有很多比如CSDN、掘金、博客园等。本人在整个学习的阶段也都会经常在上面发布文章和见解等最近学了一些开发所需要的主流框架因此以做项目代学做出了一个简易版的个人博客系统。         在这个博客系统中不需要担心安全问题因为用户密码采用了加盐加密处理破解成本高且在一些私人界面加入了拦截器等、短时间内不需要重复登录因为在redis中存储了用户的session信息并进行了持久化处理、可以随时随地地更换自己喜欢的头像因为上传的图片发送到服务器并使用Nginx存储起来稍等一段时间后台刷新后即可看到换的头像。 数据库设计 由于这是一个简易版的博客系统同时也是初代版本因此在数据库的设计中还是比较简单的只有两张表用户表和博客表。后面做下一个版本的时候可以考虑加入文章下评论的表。 用户表主要存的字段是用户id、用户名、密码、头像、创建时间其中主键是用户id且是自增的编写出下面sql语句 create table userinfo(id int primary key auto_increment,username varchar(100) not null,password varchar(100) not null,photo varchar(500) default ,createtime timestamp not null default current_timestamp,state int default 1 ) default charset utf8mb4;博客表主要存的字段是博客id、标题、内容、发布日期、发布用户、浏览量其中主键是博客id且是自增的编写出下面sql语句 create table articleinfo(id int primary key auto_increment,title varchar(100) not null,content text not null,createtime timestamp not null default current_timestamp,uid int not null,rcount int not null default 1,state int default 1 )default charset utf8mb4;主要使用到的技术点 前端 首先简单说一下本项目中前端代码的基本实现由于是前后端分离的项目所以前端需要发送请求给后端后接收来自后端的响应这里前端部分我基本使用的都是jQuery来实现的而且也基本都是使用POST发送请求相对来说会比较安全但是也不是说POST就一定好只是可能会使用的比较多具体还是需要看实际项目的开发需求来进行制定。这里额外提供出一篇文章GET和POST的区别。 后端 自定义统一返回对象 在主流的开发中基本上都会制定一套统一的返回数据形式因为这样既可以方便后端程序员在返回数据的时候不需要考虑前端是如何接收的又可以方便前端程序员在获取数据的时候不需要再去看后端返回的都有什么。不管传输的数据是何种形式都可以一一种统一的格式被获取到大大提高了开发的效率。         在返回对象之前需要先对数据进行一下封装这一步称为“统一数据返回封装”对于已经是封装好的对象直接返回即可对于返回的类型是字符串类型的则需要额外进行一步操作对于未封装过的对象直接对其进行封装后即可返回。而返回这个对象的这一步操作就称为“统一返回对象”。 ResponseAdvice类统一数据返回封装 ControllerAdvice public class ResponseAdvice implements ResponseBodyAdvice {Overridepublic boolean supports(MethodParameter returnType, Class converterType) {return true;}SneakyThrowsOverridepublic Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {//本身已经是封装好的对象if(body instanceof HashMap){return body;}//返回的类型是字符创类型Stringif(body instanceof String){ObjectMapper objectMapper new ObjectMapper();return objectMapper.writeValueAsString(AjaxResult.success(body));}return AjaxResult.success(body);} }AjaxResult类自定义统一返回对象 public class AjaxResult {//业务执行成功时返回的方法public static HashMapString, Object success(Object data){HashMapString, Object res new HashMap();res.put(code, 200);res.put(msg, );res.put(data, data);return res;}public static HashMapString, Object success(String msg, Object data){HashMapString, Object res new HashMap();res.put(code, 200);res.put(msg, msg);res.put(data, data);return res;}//业务执行失败时返回的方法public static HashMapString, Object fail(int code, String msg){HashMapString, Object res new HashMap();res.put(code, code);res.put(msg, msg);res.put(data, );return res;}public static HashMapString, Object fail(int code, String msg, Object data){HashMapString, Object res new HashMap();res.put(code, code);res.put(msg, msg);res.put(data, data);return res;} }自定义拦截器 有一些页面是需要用户登录后才能打开的如果未登录的用户强制打开就会跳转到登录页面很多网站其实基本上也都是这样操作的设置一个拦截器。         以下是设置自定义拦截器的一个模板 Component public class LoginInterceptor implements HandlerInterceptor {Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {//session中得到用户信息如果在session中得到userinfo对象说明用户已经登录否则用户未登录HttpSession session request.getSession(false);if(session ! null session.getAttribute(Constant.SESSION_USERINFO_KEY) ! null){//当前用户已经登录return true;}response.setStatus(401);return false;} } Configuration public class AppConfig implements WebMvcConfigurer {Autowiredprivate LoginInterceptor loginInterceptor;Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(loginInterceptor).addPathPatterns(/**).excludePathPatterns(excludes);} } addPathPatterns(/**)是拦截项目中全部的url而如果有一部分不需要拦截的话只需要在excludePathPatterns(excludes)中的excludes中添加不拦截url的集合即可。         为什么不直接设置拦截的url而是先全部拦截后再开放一个集合呢原因是在大部分常见的项目中拦截的是要比不拦截的多很多所以先拦截全部后再开放一部分显然是比较合理的。         对于本项目目前来说设置不拦截的url有以下这些         注意前端代码一定是不能拦截的不然页面会刷新不出来 加盐加密操作 对于加密操作可能会有很多人会想到MD5加密因为学校教的就是MD5加密MD5加密确实是不可逆的但是它会存在一个问题每次加密的结果都是一样的这样的话黑客是可以通过一张“彩虹表”来暴力枚举破解密码风险还是比较大的。         而加盐加密则不会我们这里加的盐其实是随机生成的盐值以下面这段代码为例我们制定出一个64位的密码其中前32位规定为是盐值的存储后32位规定为是加盐加密后的密码注册的时候将盐值和加盐加密后的密文拼接在一起存储在数据库中而登录的时候则是取出密文中前32位的那个盐值和用户登录时输入的那个密码进行同规则的加密后如果生成的密文与后32位的密文是相等的那么说明登录成功否则失败。 public class SecurityUtil {//加密操作public static String encrypt(String password){//每次生成内容不同但长度固定为32位的盐值String salt UUID.randomUUID().toString().replace(-, );String finalPassword DigestUtils.md5DigestAsHex((salt password).getBytes());return salt finalPassword;}//验证操作public static boolean decrypt(String password, String finalPassword){if(!StringUtils.hasLength(password) || !StringUtils.hasLength(finalPassword)){return false;}if(finalPassword.length() ! 64){return false;}String salt finalPassword.substring(0, 32);String securityPassword DigestUtils.md5DigestAsHex((salt password).getBytes());return (salt securityPassword).equals(finalPassword);} }分页功能 分页功能实现的前提是需要先知道每一页需要显示多少条数据也就是说需要先计算出一个偏移量以便于在MySQL查询中准确地进行获取数据并显示到页面。 RequestMapping(list)public ListArticleInfo getList(Integer pindex, Integer psize){if(pindex null || psize null){return null;}int offset (pindex - 1) * psize; //分页公式计算偏移量return articleService.getList(psize, offset);}对应的MyBatis语句 select idgetList resultTypecom.example.demo.model.ArticleInfoselect * from articleinfo limit #{psize} offset #{offset}/select除此之外还需要计算总页数注意这是需要页数进行向上取整操作数据数不满一页也需要计算成一页 RequestMapping(/totalpage)public Integer getTotalCount(Integer psize){if(psize ! null){int totalCount articleService.getTotalCount();return (totalCount psize) / psize;}return null;}session持久化 session持久化的目的是不需要让用户退出后短时间登录不再需要输入密码因为这样会使用户体验更加好。         对于session的持久化其实不管是mysql还是redis都是可以实现的但是目前主流的是存储到redis中所以在此之前需要先提前安装并连接好redis会在下篇文章中出教程。         其中存的话直接在用户登录的时候就可以将用户的session存起来之后设置一个超时的时间这部分是在配置文件中完成由于不管是哪一个页面都是需要对用户信息进行验证的所以可以直接在验证的时候在redis中看看是否有存在符合的session即可。 session在redis中是这样存储的如果过期则会在redis中清除 自定义头像的存储和获取 在这一步中我想了很多办法但是最终都是无法正确的实现头像的更换最后是通过Nginx来搭建一个图床用来存储图片之后这个图片就存在于公网中也就可以很容易地被获取到了。         用户上传过来的图片命名格式是用户本地的设置名字直接将这个文件名存起来的话显然是不合适的原因是如果有多个用户上传过来的图片内容不同但是文件名相同这不就冲突了吗所以我们在获取到图片之后还需要就图片进行重命名。         对图片进行重命名有两种操作方式一种是每次都随机生成一个UUID来代表文件名这样就不会出现重复的现象但是由于我们在后台就设置了不能注册相同的用户名所以我们也可以使用用户名来用作图片的命名并且将这个名字图片格式的后缀加到数据库中其实这样还有一个好处就是同一个用户对头像进行更换会对就图片进行覆盖随机的UUID则不会减少空间的占用用户量大的时候。         之后就是安装Nginx并设置文件存储的路径。 RequestMapping(/upload)public Object upload(HttpServletRequest request, MultipartFile file){HttpSession session request.getSession( false);UserInfo userInfo null;if(session ! null session.getAttribute(Constant.SESSION_USERINFO_KEY) ! null) {userInfo (UserInfo) session.getAttribute(Constant.SESSION_USERINFO_KEY);}if(file.isEmpty()){return AjaxResult.fail(-1, 请选择图片);}String originalFileName file.getOriginalFilename(); //原来图片名String[] tmp originalFileName.split(\\.);String ext . tmp[tmp.length - 1]; //取到后缀String fileName userInfo.getUsername() ext;//上传图片String pre /www/wwwroot/43.139.71.60/blog_user_img/;String path pre fileName;try {//存到外部文件夹中file.transferTo(new File(path));userService.updatePhoto(fileName, userInfo.getId());return AjaxResult.success(更换成功, 1);} catch (IOException e) {e.printStackTrace();}return AjaxResult.fail(-1, 更换失败);}项目编写过程中遇到的困难点 因为这是我真正意义上做的第一个项目所以在这个过程中遇到的困难点还是比较多的。 困难点一小 由于我一直以来都是以写后端代码为主所以对于前端页面的制作相对来说会比较困难很多时候会出现一些未知的错误调式起来也会不太适应通常都是会先用Postman先测试后端代码后再看前端如何修改等但是后面写多了其实也是有重复性的慢慢地就适应了。 困难点二小 安装redis和远程连接redis客户端需要小心一点。         由于这个项目是临时想到要添加一个session的持久化的使用也是临时在linux上安装redis的过程中出现了大意在开放了6379端口之后没有对redis设置密码导致服务器被黑客入侵后通过重装服务器解决。         教训端口不要随便开放特别是尽量不要全开对于一些容易被黑客入侵的端口最好设置一个密码更好一点。 困难点三大 用户头像更换这个问题也是困扰比较久的好在后来通过同学的指点和交流顺利解决了。         第一阶段我的思路是因为用户那边上传过来的文件是会默认存放到target文件夹下的嘛所以我使用了几个getParentFile()方法以及查找的方法来将图片移动到static文件夹下的img文件夹里面因为这样前端在获取图片的时候就可以直接获取到。当然这个思路在本地运行是完全没有问题的但是部署在linux上之后就会出现一个问题了因为项目部署是需要打包的而打的jar包在运行的时候执行getParentFile()方法是会直接跳到整个SpringBoot项目外部的图片存放位置就会出现错误后来又查阅了很多相关的文章依旧没有解决这个问题……         第二阶段我的思路是能不能在项目外找一个文件夹来存储这些图片呢说干就干在后端存储图片的时候直接就指定存储的路径在项目启动之后这次确实可以将图片成功存储进来但是无论如何前端一直报错说获取不到这个图片即使我在img标签下的src属性中使用的是绝对路径也是不能获取到图片第二种思路最后也是以失败告终……         第三阶段我的思路是突然有一次我就想到了不是还有图床这种东西吗我能不能直接自己搭建一个图床呢但是后来看到需要“氪金”的时候作为“白嫖”的我也就放弃了……         第四阶段我的思路是正当我想要通过“氪金”来解决这个问题的时候有个同学大佬跟我说了可以使用Nginx来搭建自己的图床而且还不需要“氪金”的时候更换头像的难题也就迎刃而解了~ 上传部署 当项目在本地能够顺利跑过之后接下来就是部署到服务器上了。         在部署项目之前需要提前准备好的东西有jdk1.8、redis、mysql及其库和表都需要建好。这里给出linux安装redis和mysql的教程CentOS 7 通过 yum 安装 MariaDB、安装redis、记录远程客户端连接不上redis的解决等过程。         完成上面的准备操作之后就是部署项目了将打好的jar包拉到服务器上输入命令java -jar [jar包名]就可以打开SpringBoot项目当然这样是不能让项目持久运行的只能当成一个提前的测试运行持久运行需要输入命令nohup java -jar [jar包名] 。 总结 这是我真正意义上的第一个项目有很多功能还没有实现后面版本会持续进行更新……         简单总结一下这个博客系统项目         优点使用了主流的SSMSpringBoot框架进行开发、使用Redis存储用户的session已达到持久化、对密码进行加盐加密处理、合理设置拦截器等。         缺点页面制作的不够美观、有部分代码写的还是太过于冗余、实现的功能不太够等。         关于本项目的全部代码我都放在了我的个人Gitee账户下有需要的可以点击查看个人博客系统项目存放代码。注特别需要看其中的配置文件application.yml以及所需要导入的依赖包pom.xml这决定了一个项目是否能够正常启动并运行
http://www.w-s-a.com/news/351682/

相关文章:

  • 开福区城乡建设局门户网站关键词挖掘查询工具爱站网
  • 网站建设全国排名沈阳seo按天计费
  • 成都公司网站设计无锡seo网站推广费用
  • 建网站平台要多少钱购物网站界面设计策划
  • 学完js了可以做哪些网站长沙建站官网
  • 怎么样做问卷网站多少钱英语
  • 房产网站建设方案建筑公司是干什么的
  • wordpress建的大型网站柳州市网站建设
  • 石家庄做网站的公司有哪些微信自媒体网站建设
  • 池州哪里有做网站注册公司有哪些风险
  • 做古代风格头像的网站对网站政务建设的建议
  • 网站搜索栏怎么做设计个网站要多少钱
  • 阿里巴巴网站建设目标wamp wordpress
  • 自己做的网站怎么挂网上金蝶erp
  • 网站的页面由什么组成淘宝网网站建设的需求分析
  • 软文网站推广法dede5.7内核qq个性门户网站源码
  • 个人备案网站名称校园网站建设特色
  • vr超市门户网站建设班级网站怎么做ppt模板
  • 网站建设一般是用哪个软件刚开始做写手上什么网站
  • 用jsp做的网站源代码下载有哪些做红色旅游景点的网站
  • 网站开发的技术选型黄石市网站建设
  • 做直播网站需要证书吗专做宝宝的用品网站
  • 网站标题用什么符号网站制作交易流程
  • dede模板网站教程jsp网站搭建
  • 上海网站开发外包公司鲜花导购网页制作
  • 宿州外贸网站建设公司个人注册网站一般做什么
  • 小公司做网站用哪种服务器什么是网站代理
  • 青岛李村网站设计公司cms建站平台
  • 做saas网站可行吗许昌抖音推广公司
  • 网站建设找谁做seo基础知识培训