实训笔记
第一天
事务回滚 extends runtimeException
return Interger
Session 清空密码
throw new ServiceException
MD5加密
第二天
部署项目所需注意
创建spring Boot项目
热部署 :开发工具 web-tools
搜索引擎
@Test
测试数据源
同一个用户不能创建相同的笔记名称
用户名是否重复
序列化 1L implements serialzable
注册
用户名判断>>>>返回 user
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BiTk4ALS-1587123105178)(C:\Users\刘\AppData\Roaming\Typora\typora-user-images\1559007907990.png)]
select * >>不推荐
select id,uname,upwd,phone,email from t_user where uname=#{uname}?规范
select count(*) cnt from t_user where uphone=#{uphone}
映射文件 :约束>>>>>>
1、validate
2、namespace
<mapper namespace="com.sx.ybj.mapper">
<!-- sql注释>
<select id="方法" parameterType="String" or "pojo">
</mapper>
别名>>>> aliaes-package>>>别名
@MapperBean
单元测试
src/java/test
1、自定义业务异常
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FXhjH27Q-1587123105180)(C:\Users\刘\Desktop\工具\7019.png)]
throws ServiceException 抛出异常>>>>>>>1自定义异常 2抛出自定义异常
1、单元测试
2、集成测试
Result<void>
Post 和 Get
模拟测试:>>>单元测试>>>>绕过调用
第三天
项目开发过程任务
需求分析 数据流图 、数据字典、
概要设计:软件结构图
详细设计:(程序算法、数据库设计)
程序算法:程序流程图、NS方框图、判定书、判定表
数据库设计:ER实体练习图(表结构说明)
第二三周、编码>>>>>程序开发文档
最后一个星期做测试>>>>>>>(黑盒测试、白盒测试)
每个阶段复审
第四天
提交:
原型图
需求分析
数据库设计
编写
1、小组会议纪要: 确定工作计划
2、小组周工作计划:完成计划
3、个人周工作计划
4、个人周工作总结
5、小组周工作总结:工作总结
项目规范
1、add
2、get
3、update
4、delete
第五天
springboot 以jar方式在linux后台运行
linux命令如下:
nohup java -jar 自己的springboot项目.jar >日志文件名.log 2>&1 &
nohup java -jar ybj-0.0.1-SNAPSHOT.jar >ybj.log 2>&1 &
netstat -tlunp
kill pid
命令解释:
nohup:不挂断地运行命令,退出帐户之后继续运行相应的进程。
java -jar 自己的springboot项目.jar:执行springboot的项目,如果单单只执行该命令,linux只会短暂的运行该项目,当退出控制台后会自动关闭该项目。
>日志文件名.log:是nohup把command的输出重定向到当前目录的指定的“日志文件名.log”文件中,即输出内容不打印到屏幕上,而是输出到”日志文件名.log”文件中。不指定文件名会在当前目录创建nohup.out,如果当前目录的 nohup.out 文件不可写,输出重定向到 $HOME/nohup.out 文件中。如果没有文件能创建或打开以用于追加,那么 Command 参数指定的命令不可调用。
2>&1:2就是标准错误,1是标准输出,该命令相当于把标准错误重定向到标准输出么。这里&相当于标准错误等效于标准输出,即把标准错误和标准输出同时输出到指定的“日志文件名.log”文件中。
最后的&:让改作业在后台运行。
spring security跨域调用>前台携带 cookie
//spring security解决跨域调用
.and().cors().and().csrf().disable();
package com.sx.ybj.config;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
/**
* @program: ybj
* @description: 跨域访问
* @author: lwx
* @create: 2019-05-15 08:36
*/
@Configuration
@AutoConfigureBefore(HelloSecurity.class)
public class ORSConfiguration extends WebMvcConfigurerAdapter {
// @Override
/**
*@Description: addMapping:配置可以被跨域的路径,可以任意配置,可以具体到直接请求路径。
* allowedMethods:允许所有的请求方法访问该跨域资源服务器,如:POST、GET、PUT、DELETE等。
* allowedOrigins:允许所有的请求域名访问我们的跨域资源,可以固定单条或者多条内容,如:”http://www.aaa.com“,只有该域名可以访问我们的跨域资源。
* allowedHeaders:允许所有的请求header访问,可以自定义设置任意请求头信息。
*@Param: [registry]
*@return: void
*@Author: your name
*@date: 2019/5/15
*/
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedMethods("*")
.allowedOrigins("*")
.allowedHeaders("*")
.allowCredentials(true)
.maxAge(3600);
}
}
第九天
头像上传
为UploadController.java 新增upload用来接受上传
1. 接受上传的文件
@RequestParam("file") MultipartFile file
2. 根据时间戳创建新的文件名,这样即便是第二次上传相同名称的文件,也不会把第一次的文件覆盖了
String fileName = System.currentTimeMillis()+file.getOriginalFilename();
3. 通过req.getServletContext().getRealPath("") 获取当前项目的真实路径,然后拼接前面的文件名
String destFileName=req.getServletContext().getRealPath("")+"uploaded"+File.separator+fileName;
4. 第一次运行的时候,这个文件所在的目录往往是不存在的,这里需要创建一下目录
File destFile = new File(destFileName);
destFile.getParentFile().mkdirs();
5. 把浏览器上传的文件复制到希望的位置
file.transferTo(destFile);
6. 把文件名放在model里,以便后续显示用
m.addAttribute("fileName",fileName);
package com.sx.ybj.controller.user;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
/**
* @program: ybj
* @description: 上传图片
* @author: lwx
* @create: 2019-06-04 15:37
*/
@Controller
public class UploadController {
@RequestMapping("/uploadPage")
public String uploadPage() {
return "uploadPage";
}
@RequestMapping(value = "/upload", method = RequestMethod.POST)
public String upload(HttpServletRequest req, @RequestParam("file") MultipartFile file, Model m) {
try {
String fileName = System.currentTimeMillis()+file.getOriginalFilename();
String destFileName=req.getServletContext().getRealPath("")+"uploaded"+ File.separator+fileName;
File destFile = new File(destFileName);
destFile.getParentFile().mkdirs();
file.transferTo(destFile);
m.addAttribute("fileName",fileName);
} catch (FileNotFoundException e) {
e.printStackTrace();
return "上传失败," + e.getMessage();
} catch (IOException e) {
e.printStackTrace();
return "上传失败," + e.getMessage();
}
return "showImg";
}
}
第十天
用户信息验证
package com.sx.ybj.service.user.Impl;
import com.sx.ybj.mapper.UserMapper;
import com.sx.ybj.pojo.User;
import com.sx.ybj.pojo.UserExample;
import com.sx.ybj.service.user.UserInfoService;
import com.sx.ybj.utils.YbjResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* @program: ybj
* @description: 用户信息
* @author: lwx
* @create: 2019-06-04 14:54
*/
@Service
public class UserInfoServiceImpl implements UserInfoService {
@Autowired
UserMapper userMapper;
@Override
public YbjResult checkInfo(String value, String type) throws Exception {
// TODO Auto-generated method stub
boolean result = false;
//type为类型,可选参数1、2、3分别代表username、phone、email
if ("1".equals(type)) {
result= checkUserName(value);
} else if ("2".equals(type)) {
result = checkEmil(value);
}
//返回结果
if (result) {
return YbjResult.build(1,"不存在该数值",result);
}
return YbjResult.build(0, "此数值已经存在",result);
}
//ture 为不存在
private boolean checkUserName(String username) throws Exception {
//创建查询条件
UserExample example = new UserExample();
UserExample.Criteria criteria = example.createCriteria();
criteria.andUsernameEqualTo(username);
List<User> list = userMapper.selectByExample(example);
//判断结果中是否存在
if (list == null || list.isEmpty()) {
return true;
}
return false;
}
private boolean checkEmil(String eamil) throws Exception {
//创建查询条件
UserExample example = new UserExample();
UserExample.Criteria criteria = example.createCriteria();
criteria.andUserEmailEqualTo(eamil);
List<User> list = userMapper.selectByExample(example);
//判断结果中是否存在
if (list == null || list.isEmpty()) {
return true;
}
return false;
}
}
后台管理>.>>>
第十一天
笔记上传
@RequestMapping(value = "/uploadNote", method = RequestMethod.POST)
public String uploadNote(HttpServletRequest req, @RequestParam("file") MultipartFile file,Model m,Notebook notebook) throws Exception{
String html=null;
String fileName=System.currentTimeMillis()+file.getOriginalFilename();//获取源文件名称
// String destFileName=req.getServletContext().getRealPath("")+"uploaded"+File.separator+fileName;//生成下载路径
// String destFileName="/usr/local/tmp2"+"uploaded"+fileName;
String destFileName="/usr/local/tmp2/"+fileName;
File destFile = new File(destFileName);//生成文件路径
destFile.getParentFile().mkdirs();
file.transferTo(destFile);//生成文件
FileInputStream fileInputStream=new FileInputStream(destFile);//文件输入流
byte[] all =new byte[(int) destFile.length()];//文件长度
while (fileInputStream.read(all) != -1) {
html = new String(all);
}
PegDownProcessor pdp = new PegDownProcessor(Integer.MAX_VALUE);
html = pdp.markdownToHtml(html);//生成html文件
notebook.setNotebookTitle(file.getOriginalFilename());
notebook.setCategorizeId(1);
notebook.setNotebookContent(html);
noteService.createNote(notebook);
m.addAttribute("md",html);
return "/home";
}
第十二天
逆向工程遇到的问题
1、字符长度溢出
<!--<table tableName="activity" domainObjectName="Activity"-->
<!--enableCountByExample="true" enableDeleteByExample="true"-->
<!--enableSelectByExample="true" enableUpdateByExample="true" >-->
<!--<columnOverride column="activity_content" jdbcType="VARCHAR"/>-->
<!--</table>-->
2、创建笔记,返回笔记Id
<table tableName="categorize" domainObjectName="Categorize"
enableCountByExample="true" enableDeleteByExample="true"
enableSelectByExample="true" enableUpdateByExample="true" >
<generatedKey column="categorize_id" sqlStatement="MySql" identity="true" />
</table>
下载笔记
Springboot对资源的描述提供了相应的接口
https://www.cnblogs.com/yaowen/p/8918678.html
其主要实现类有ClassPathResource、FileSystemResource、UrlResource、ByteArrayResource、
ServletContextResource和InputStreamResource。
- ClassPathResource可用来获取类路径下的资源文件。假设我们有一个资源文件test.txt在类路径下,我们就可以通过给定对应资源文件在类路径下的路径path来获取它,new ClassPathResource(“test.txt”)。
- FileSystemResource可用来获取文件系统里面的资源。我们可以通过对应资源文件的文件路径来构建一个FileSystemResource。FileSystemResource还可以往对应的资源文件里面写内容,当然前提是当前资源文件是可写的,这可以通过其isWritable()方法来判断。FileSystemResource对外开放了对应资源文件的输出流,可以通过getOutputStream()方法获取到。
- UrlResource可用来代表URL对应的资源,它对URL做了一个简单的封装。通过给定一个URL地址,我们就能构建一个UrlResource。
- ByteArrayResource是针对于字节数组封装的资源,它的构建需要一个字节数组。
- ServletContextResource是针对于ServletContext封装的资源,用于访问ServletContext环境下的资源。ServletContextResource持有一个ServletContext的引用,其底层是通过ServletContext的getResource()方法和getResourceAsStream()方法来获取资源的。
- InputStreamResource是针对于输入流封装的资源,它的构建需要一个输入流。
Resource接口中主要定义有以下方法:
- exists():用于判断对应的资源是否真的存在。
- isReadable():用于判断对应资源的内容是否可读。需要注意的是当其结果为true的时候,其内容未必真的可读,但如果返回false,则其内容必定不可读。
- isOpen():用于判断当前资源是否代表一个已打开的输入流,如果结果为true,则表示当前资源的输入流不可多次读取,而且在读取以后需要对它进行关闭,以防止内存泄露。该方法主要针对于InputStreamResource,实现类中只有它的返回结果为true,其他都为false。
- getURL():返回当前资源对应的URL。如果当前资源不能解析为一个URL则会抛出异常。如ByteArrayResource就不能解析为一个URL。
- getFile():返回当前资源对应的File。如果当前资源不能以绝对路径解析为一个File则会抛出异常。如ByteArrayResource就不能解析为一个File。
- getInputStream():获取当前资源代表的输入流。除了InputStreamResource以外,其它Resource实现类每次调用getInputStream()方法都将返回一个全新的InputStream。
- 以及一些类似于Java中的File的接口,比如getName,getContenLength等等。
如果需要获取本地文件系统中的指定路径下的文件,有一下几种方式
-
通过ResponseEntity实现
-
通过写HttpServletResponse的OutputStream实现
-
功能实现
-
@RequestMapping("/downloadOnlineLearnMaterials") public String downloadFile(HttpServletRequest request, HttpServletResponse response,int notebookId) { //String fileName = "hehe.md";// 设置文件名,根据业务需要替换成要下载的文件名 String fileName=notebookMapper.selectByPrimaryKey(notebookId).getNotebookUrl();//查询笔记的路径 if (fileName != null) { //设置文件路径 // String realPath = "F:\\IDE"; String realPath=fileName; //File file = new File(realPath, fileName); //文件 File file=new File(realPath); if (file.exists()) { response.setContentType("application/force-download");// 设置强制下载不打开 response.addHeader("Content-Disposition", "attachment;fileName=" + fileName);// 设置文件名 byte[] buffer = new byte[1024];//设置缓存byte数组 FileInputStream fis = null;//文件输入流 BufferedInputStream bis = null;//缓存流 try { fis = new FileInputStream(file); bis = new BufferedInputStream(fis);//缓存输入流 OutputStream os = response.getOutputStream();//输出流 int i = bis.read(buffer);//二进制流 while (i != -1) { os.write(buffer, 0, i);//写入 i = bis.read(buffer); } System.out.println("success"); } catch (Exception e) { e.printStackTrace(); } finally { if (bis != null) { try { bis.close(); } catch (IOException e) { e.printStackTrace(); } } if (fis != null) { try { fis.close(); } catch (IOException e) { e.printStackTrace(); } } } } } return null; }
### 搜索引擎
1.代码高亮显示
### 配置文件如下
服务器发送邮件: 打开 25 端口
````properties
#mysql
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.url=jdbc:mysql://106.14.145.180/cloud_note?useUnicode=true&characterEncoding=UTF-8
spring.datasource.username=root
spring.datasource.password=admin
mybatis.config-location=classpath:/mybatis-config.xml
#mybatis.mapper-locations=classpath:/mapper/*.xml
server.context-path=/note
#文件上传下载
spring.http.multipart.maxFileSize=10Mb
spring.http.multipart.maxRequestSize=10Mb
server.port=8081
#安全
logging.level.org.springframework.security=info
#security.basic.enabled = false
security.user.name=sang
security.user.password=123
#热部署
spring.thymeleaf.cache=false
spring.devtools.restart.enabled=true
spring.devtools.restart.additional-paths=src/main/java
#pojo
mybatis.type-aliases-package=com.sx.ybj.pojo
#搜索引擎
spring.data.elasticsearch.cluster-name=elasticsearch
#spring.data.elasticsearch.cluster-nodes=127.0.0.1:9300
spring.data.elasticsearch.cluster-nodes=106.14.145.180:9300
#邮箱
spring.mail.username=@qq.com
spring.mail.password=yfyzznsrxttmccdg
spring.mail.host=smtp.qq.com
spring.mail.properties.mail.smtp.enable=true;
spring.mail.port=587
#redis
###########################redis#########################
#Redis数据库索引(默认为0)
spring.redis.database=0
#Redis服务器地址
spring.redis.host=106.14.145.180
#Redis服务器连接端口
spring.redis.port=6379
#Redis服务器连接密码(默认为空)
spring.redis.password=
#连接池最大连接数(使用负值表示没有限制)
spring.redis.pool.max-active=10
#连接池最大阻塞等待时间(使用负值表示没有限制)
spring.redis.pool.max-wait=-1
#连接池中的最大空闲连接
spring.redis.pool.max-idle=8
#连接池中的最小空闲连接
spring.redis.pool.min-idle=0
#连接超时时间(毫秒)
spring.redis.timeout=0
spring.jpa.show-sql=true
第十三天
获取用户反馈信息的空指针异常
if (userServices.getFeedBack().size()>0&&userServices.getFeedBack()!=null)
out.write(JsonUtils.objectToJson(YbjResult.ok(userServices.getFeedBack().get(0))));
else
out.write("{\"status\":\"1\",\"msg\":\"登录成功\"}");
spring boot Controller获取参数注解总结
总结下获取参数的注解
注解 作用
@Controller 处理http请求
@RestController Spring4之后新加的注解,作用和原来的@ResponseBody配合@Controller相同。用于返回Json
@PathVariable 获取url中的参数
@RequestParam 获取请求参数的值
@RequestMapping 配置url映射,需要多个时可以将value写成一个集合
@GetMapping 组合注解,相当于@RequestMapping(method = RequestMethod.GET)
@PostMapping 组合注解,相当于@RequestMapping(method = RequestMethod.POST)
@PathVariable
获取url里面的参数
e.g http://localhost:8080/user/123
@RequestMapping(value = "/user/{id}" ,method = RequestMethod.GET)
public int hi(@PathVariable("id") int id){
return id;
}
@RequestParam
获取url里面?后面的参数
e.g http://locahost:8080/user?id=123
@RequestMapping(value = "/user/{id}" ,method = RequestMethod.GET)
public int hi(@RequestParam(value="id",defaultValue=2,required=false) int id){
return id;
}
里面参数很好用,defaultValue默认值,required为false时允许传过来的值为空
创建笔记时,默认笔记
if (notebook.getCategorizeId()==null){
CategorizeExample categorizeExample=new CategorizeExample();
CategorizeExample.Criteria criteria=categorizeExample.createCriteria();
criteria.andUserIdEqualTo(Util.getCurrentUser().getUserId())
.andCategorizeNameEqualTo("默认笔记");
int id=categorizeMapper.selectByExample(categorizeExample).get(0).getCategorizeId();
notebook.setCategorizeId(id);
}
第十四天
搜索引擎配置
<!--pom-->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
@Document(indexName = "notebook",type = "note")//文档>索引
@Id
private Integer notebookId; >索引ID
@GetMapping("/searchFeedback")
public YbjResult serarchFeedback(String content){
try {
//初始化数据
List<Feedback> feedbacks=feedbackMapper.selectByExample(null);
for (Feedback feedback:feedbacks){
feedbackImpl.index(feedback);
}
//查询数据
return YbjResult.ok(feedbackImpl.findByFeedbackContentLike(content));
} catch (Exception e) {
return YbjResult.build(0,"失败",ExceptionUtil.getStackTrace(e));
}
}
关于redis缓存
@Override
@CacheEvict(allEntries=true) //清除缓存
@CacheConfig(cacheNames="category") //设置缓存
@Override
@Cacheable(key="'category '+#userId") //添加缓存
关于springsecurity
1、pom依赖
<!--安全-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
2、java
#安全
logging.level.org.springframework.security=info //打印安全日志
#security.basic.enabled = false//关闭安全
security.user.name=sang
security.user.password=123
package com.sx.ybj.service;
import com.sx.ybj.mapper.RolesMapper_1;
import com.sx.ybj.mapper.UserMapper;
import com.sx.ybj.pojo.Roles;
import com.sx.ybj.pojo.User;
import com.sx.ybj.pojo.UserExample;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@Service
@Transactional
public class UserService implements UserDetailsService {
@Autowired
RolesMapper_1 rolesMapper;
@Autowired
UserMapper userMapper;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
//获得用户名
UserExample userExample=new UserExample();
UserExample.Criteria criteria=userExample.createCriteria();
criteria.andUsernameEqualTo(username);
List<User> users=userMapper.selectByExample(userExample);
User user=users.get(0);
if (user == null) {
//避免返回null,这里返回一个不含有任何值的User对象,在后期的密码比对过程中一样会验证失败
return new User();
}
//查询用户的角色信息,并返回存入user中
List<Roles> roles = rolesMapper.getRolesByUid(user.getUserId());
user.setRoles(roles);
return user;
}
}
//用户角色设置
pojo
@Override
@JsonIgnore
public Collection<? extends GrantedAuthority> getAuthorities() {
List<GrantedAuthority> authorities = new ArrayList<>();
for (Roles role : roles) {
authorities.add(new SimpleGrantedAuthority("ROLE_" + role.getName()));
}
return authorities;
}
//用户权限
@Override
public boolean isEnabled() {
if (this.enabled.equals("1"))
return true;
else
return false;
}
3、config
package com.sx.ybj.config;
import com.sx.ybj.service.UserService;
import com.sx.ybj.utils.JsonUtils;
import com.sx.ybj.utils.YbjResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.util.DigestUtils;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
@Configuration
@EnableWebSecurity
@Order(-1)
public class HelloSecurity extends WebSecurityConfigurerAdapter {
@Autowired
UserService userService;
@Autowired
com.sx.ybj.service.user.UserService userServices;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.headers().frameOptions().disable();
//请求权限配置
http.authorizeRequests()
//指定了/login不需要任何认证就可以访问,
.antMatchers("/user/checkInfo","/user/getOneShareNote/*","/user/login","/user/reg","/index","/user/findShareNote","/user/updatePwdWL","/user/getCode","/home","/getOneShareNotes/*").permitAll()
.antMatchers("/hello","/admin/*").hasRole("超级管理员")
//任何请求,登录后方可访问。
.anyRequest().authenticated()
//登陆界面参数
// .and().formLogin().loginPage("/login").permitAll()
.and().formLogin().loginProcessingUrl("/user/login").permitAll().successHandler(new AuthenticationSuccessHandler() {
//成功时候调用的方法
@Override
public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
httpServletResponse.setContentType("application/json;charset=utf-8");
PrintWriter out = httpServletResponse.getWriter();
// out.write("{\"status\":\"1\",\"msg\":\"登录成功\"}");
if (userServices.getFeedBack().size()>0&&userServices.getFeedBack()!=null)
out.write(JsonUtils.objectToJson(YbjResult.ok(userServices.getFeedBack().get(0))));
else
out.write("{\"status\":\"1\",\"msg\":\"登录成功\"}");
out.flush();
out.close();
}
}).failureHandler(new AuthenticationFailureHandler() {
@Override
public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
httpServletResponse.setContentType("application/json;charset=utf-8");
PrintWriter out = httpServletResponse.getWriter();
out.write("{\"status\":\"error\",\"msg\":\"登录失败\"}");
out.flush();
out.close();
}
})
//设置注销成功后跳转页面,默认是跳转到登录页面
.and().logout()
//权限访问失败界面,关键,如果不定义的话会抛出异常
.and().exceptionHandling().accessDeniedPage("/").and().cors().and().csrf().disable();
// http.cors().configurationSource(CorsConfigurationSource());
}
// private CorsConfigurationSource CorsConfigurationSource() {
// CorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
// CorsConfiguration corsConfiguration = new CorsConfiguration();
// corsConfiguration.addAllowedOrigin("http://localhost:8080"); //同源配置,*表示任何请求都视为同源,若需指定ip和端口可以改为如“localhost:8080”,多个以“,”分隔;
// corsConfiguration.addAllowedHeader("*");//header,允许哪些header,本案中使用的是token,此处可将*替换为token;
// corsConfiguration.addAllowedMethod("*"); //允许的请求方法,PSOT、GET等
// ((UrlBasedCorsConfigurationSource) source).registerCorsConfiguration("/**",corsConfiguration); //配置允许跨域访问的url
// return source;
// }
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
System.out.println("不用测试了这里程序运行第一个进入");
auth.userDetailsService(userService)
.passwordEncoder(new PasswordEncoder() {
@Override
public String encode(CharSequence charSequence) {
return DigestUtils.md5DigestAsHex(charSequence.toString().getBytes());
}
@Override
public boolean matches(CharSequence charSequence, String s) {
return s.equals(DigestUtils.md5DigestAsHex(charSequence.toString().getBytes()));//判断密码
}
});
}
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/static/**");//静态资源处理
}
@Bean
AccessDeniedHandler getAccessDeniedHandler() {
return new AuthenticationAccessDeniedHandler();
}
}
关于回收站
/**
*根据笔记本ID查询笔记本下的笔记
* @param categorizerId
* @return
*/
1·删除笔记本
1.1 删除笔记本时笔记本有笔记不能删除
1.2 将笔记本状态变成0
2.恢复笔记本
2.恢复笔记
2.1修改笔记状态
2.2修改笔记本状态
搭建图片服务器
https://www.cnblogs.com/shuaifing/p/8268949.html
2.安装的依赖环境准备
a. 安装gcc的环境, yum install gcc-c++
第十五天
异常处理
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gko1Fy7W-1587123105181)(C:\Users\刘\AppData\Roaming\Typora\typora-user-images\1560392830616.png)]
RuntimeException如果使用try和catch异常可以被捕捉。
错误Error不 能够被捕捉
运行时异常与非运行时异常的区别
Throwable 是所有 Java 程序中错误处理的父类 ,有两种子类: Error 和 Exception 。
Error :表示由 JVM 所侦测到的无法预期的错误,由于这是属于 JVM 层次的严重错误 ,导致 JVM
无法继续执行,因此,这是不可捕捉到的,无法采取任何恢复的操作,顶多只能显示错误信息。
Exception :表示可恢复的例外,这是可捕捉到的。
Java 提供了两类主要的异常 :runtime exception 和 checked exception 。 checked
异常也就是我们经常遇到的 IO 异常,以及 SQL 异常都是这种异常。 对于这种异常, JAVA 编译器强制要求我们必需对出现的这些异常进行
catch 。所以,面对这种异常不管我们是否愿意,只能自己去写一大堆 catch 块去处理可能的异常。
但是另外一种异常: runtime exception ,也称运行时异常,我们可以不处理。当出现这样的异常时,总是由虚拟机
接管。比如:我们从来没有人去处理过 NullPointerException 异常,它就是运行时异常,并且这种异常还是最常见的异常之一。
出现运行时异常后,系统会把异常一直往上层抛,一直遇到处理代码。如果没有处理块,到最上层,如果是多线程就由 Thread.run() 抛出
,如果是单线程就被 main() 抛出
。抛出之后,如果是线程,这个线程也就退出了。如果是主程序抛出的异常,那么这整个程序也就退出了。运行时异常是
Exception 的子类,也有一般异常的特点,是可以被 Catch
块处理的。只不过往往我们不对他处理罢了。也就是说,你如果不对运行时异常进行处理,那么出现运行时异常之后,要么是线程中止,要么是主程序终止。
如果不想终止,则必须扑捉所有的运行时异常,决不让这个处理线程退出。队列里面出现异常数据了,正常的处理应该是把异常数据舍弃,然后记录日志。不应该由于异常数据而影响下面对正常数据的处理。
在这个场景这样处理可能是一个比较好的应用,但并不代表在所有的场景你都应该如此。如果在其它场景,遇到了一些错误,如果退出程序比较好,这时你就可以不太理会运行时异常
,或者是通过对异常的处理显式的控制程序退出
冒泡排序
1、初始化数组
2、1 2 5 3 2 8 3 7
3、 第一糖冒泡 1 2 3 2 5 3 7 8
聚合排序
//聚合方式
String name =heroes
.stream()
.sorted((h1,h2)->h1.hp>h2.hp?-1:1)
.skip(2)
.map(h->h.getName())
.findFirst()
.get();
System.out.println("通过聚合操作找出来的hp第三高的英雄名称是:" + name);
第十六天
关于最近笔记的日期的排序
@Override
public List<Notebook> getNewNote(int userId) {
Date date1=new Date();
NotebookExample notebookExample=new NotebookExample();
NotebookExample.Criteria criteria= notebookExample.createCriteria();
criteria.andUserIdEqualTo(userId).andNotebookStateEqualTo(1);
List<Notebook> notebooks= notebookMapper.selectByExample(notebookExample);
List<Notebook> notebooks1=new ArrayList<>();
for (Notebook notebook:notebooks){
long day=(date1.getTime()-notebook.getNotebookModfiy().getTime()+1000000)/(60*60*24*1000);//找出最近十天的笔记
if (day<=10)
notebooks1.add(notebook);
}
//按照修改时间排序
List<Notebook> notebooks2=new ArrayList<>();
// SimpleDateFormat simpleDateFormat=new SimpleDateFormat("yyyy-MM-dd HH-mm-ss");
notebooks1.stream().sorted((n1,n2)->(n1.getNotebookModfiy().getTime()>n2.getNotebookModfiy().getTime()?-1:1)).forEach(notebook ->notebooks2.add(notebook));
// notebooks1.stream().forEach(notebook -> System.out.println(simpleDateFormat.format(notebook.getNotebookModfiy())));
return notebooks2;
}
笔记本 保存
@RequestMapping("/saveContent")
@ResponseBody
public YbjResult downloadFile(int notebookId) throws Exception{
Notebook notebook = notebookMapper.selectByPrimaryKey(notebookId);
String nbName =System.currentTimeMillis()+ notebook.getNotebookTitle()+".md" ;//获得文件名称
String url=notebook.getNotebookUrl();//获得文件路径
String content=notebook.getNotebookContent();//获得内容
//删除原先的笔记
if (url!=null){
File file=new File(url);
file.delete();
}
url="/usr/local/tmp2/upload/";//定义路径
File file = new File(url+nbName);
file.createNewFile(); //创建文件
try (FileWriter fr = new FileWriter(file)) {
// 以字符流的形式把数据写入到文件中
char[] cs = content.toCharArray();
fr.write(cs); //写入文件
//添加url
notebook.setNotebookUrl(url+nbName);
notebookMapper.updateByPrimaryKeySelective(notebook);
return YbjResult.ok();
} catch (IOException e) {
// TODO Auto-generated catch block
return YbjResult.build(0,"保存失败", ExceptionUtil.getStackTrace(e));
}
}
第十七天
关于下载笔记本乱码
response.setHeader("Content-Disposition", "attachment;fileName=" + URLEncoder.encode( notebook.getNotebookTitle()+".md","UTF-8") );// 设置文件名
关于云笔记业务逻辑
一、
1、用户都能收藏自己的笔记,和共享的笔记<且不需要分类到文件夹>
2、收藏的笔记都只显示再我的收藏里面
3、共享笔记显示已经收藏的笔记
4、收藏笔记同意放到我的收藏夹文件夹里面去
5、注册用户默认创建一个收藏夹,且不能删除
二、
1、最近笔记:查询最近修改的笔记 ok
2、与我分享:查询共享笔记,且标记是否被共享,可以收藏未共享的笔记 ok
3、我的收藏:根据用户名,显示自己已经收藏的笔记 ok
4、我的笔记本:显示自己创建的笔记本 ok
5、我的笔记:显示笔记本下的笔记,和自己收藏的笔记本,并且标明状态 ok
6、收藏笔记:收藏到自己创建的文件夹下面
第十八天
路径问题
环境:springboot 1.5.2,thymeleaf
情况:在开发环境下正常,但使用jar运行时,报错Error resolving template template might not exist or might not be accessible,意思是模板页不在,但在jar里存在该模板页
1、解决方法:原因是指向模板的路径前有斜杆/,就会出错,去掉就正常了(路径前不能带斜杆,类似相对路径的写法)
网上有人说增加配置spring.thymeleaf.prefix=classpath:/templates也能解决
2、恢复笔记本空指针异常
下载笔记返回return结果
b
@Override
public YbjResult deleteNotebook(int categorizeId) {
try {
NotebookExample notebookExample=new NotebookExample();
NotebookExample.Criteria criteria=notebookExample.createCriteria();
criteria.andCategorizeIdEqualTo(categorizeId).andNotebookStateEqualTo(1);
List<Notebook> notebooks=notebookMapper.selectByExample(notebookExample);
if (!notebooks.isEmpty()){
return YbjResult.build(0,"no","笔记本下面有笔记,删除失败 ");
}
Categorize categorize=categorizeMapper.selectByPrimaryKey(categorizeId);
if (categorize.getCategorizeName().equals("默认笔记")){
return YbjResult.build(0,"no","不能删除默认笔记");
}
//判断回收站是否有笔记,没有的话失败
NotebookExample notebookExample1=new NotebookExample();
NotebookExample.Criteria criteria2=notebookExample1.createCriteria();
criteria2.andCategorizeIdEqualTo(categorizeId).andNotebookStateEqualTo(0);
List<Notebook> notebooks3=notebookMapper.selectByExample(notebookExample1);
if (notebooks3.isEmpty()){
categorizeMapper.deleteByPrimaryKey(categorizeId);
return YbjResult.build(1,"彻底删除成功");
}
categorize.setCategorizeState(0);
return YbjResult.ok( categorizeMapper.updateByPrimaryKeySelective(categorize));
} catch (Exception e) {
return YbjResult.build(0, "异常", ExceptionUtil.getStackTrace(e));
}
}
@Test
public void get1() throws Exception{
String content=notebookMapper.selectByPrimaryKey(227).getNotebookContent();
String conten1 =content.replaceAll("\\&[a-zA-Z]{1,10};", "").replaceAll("<[^>]*>", "").replaceAll("[(/>)<]", "");
System.out.println(conten1);
}
第十九天
bug:
-
修改个人信息时,用户邮箱设空,导致以后不能修改密码
-
后台搜索反馈信息把管理员反馈信息搜索出来,或者也可以获得自己的反馈信息
-
管理员不能够禁用管理员
-
收藏之后,不能删除其他用户的笔记或者修改 ok 已修复
-
不能查看自己分享的笔记
-
public static boolean isEmail(String string) { if (string == null) return false; String regEx1 = "^([a-z0-9A-Z]+[-|\\.]?)+[a-z0-9A-Z]@([a-z0-9A-Z]+(-[a-z0-9A-Z]+)?\\.)+[a-zA-Z]{2,}$"; Pattern p; Matcher m; p = Pattern.compile(regEx1); m = p.matcher(string); if (m.matches()) return true; else return false; } --------------------- 作者:Danishlyy1995 来源:CSDN 原文:https://blog.csdn.net/u012934325/article/details/73558084/ 版权声明:本文为博主原创文章,转载请附上博文链接!
GitHub的使用
项目的下载,查看和修改
第一步. 从GitHub上下载我们的项目代码。
-
以Hello-World项目为例,点击绿色按钮Clone or download,然后在弹出窗口中点击剪切板图标,复制仓库的URL。
-
在git bash中输入git clone https://github.com/feicui-android/Hello-World.git,下载项目源码。
第二步. 查看版本历史
-
cd到项目文件夹下,使用git log能看到我们的历史提交记录。
-
要回到某一历史版本,可以使用git checkout commitId,看完后要回到最新代码,使用git checkout master。
第三步. 本地修改代码
你可以在我们的代码基线上任意修改,但为了下载新代码时不出现冲突,请遵循以下步骤:
-
下载新代码:git pull。
-
从master出捡出一个新的分支:git checkout -b feature。feature是分支名称,你可以随意取名,但请用英文。
-
在feature分支上随意修改,改完后你可以提交你的修改:git commit -m “some message”。
-
此时要同步代码,请先切回主分支:git checkout master,然后更新git pull。
-
如果想删除自己建立的分支,使用git branch -D feature,注意执行此命令后分支被强制删除,无法恢复。
————————————————
版权声明:本文为CSDN博主「n大橘为重n」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/buknow/article/details/80325986