输出
Java提供的输出包括:System.out.println()
/ print()
/ printf()
其中printf()
可以格式化输出
输入
Java提供Scanner对象来方便输入,读取对应的类型可以使用:
scanner.nextLine()
/ nextInt()
/ nextDouble()
/ ...
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in); // 创建Scanner对象
System.out.print("Input your name: "); // 打印提示
String name = scanner.nextLine(); // 读取一行输入并获取字符串
System.out.print("Input your age: "); // 打印提示
int age = scanner.nextInt(); // 读取一行输入并获取整数
System.out.printf("Hi, %s, you are %d\n", name, age); // 格式化输出
}
}
判断引用类型相等
在Java中,判断值类型的变量是否相等,可以使用==
运算符。但是,判断引用类型的变量是否相等,==
表示“引用是否相等”,或者说,是否指向同一个对象。例如,下面的两个String类型,它们的内容是相同的,但是,分别指向不同的对象,用==
判断,结果为false
要注意浮点数判断相等不能直接用==
运算符,浮点数在计算机中常常无法精确表示,并且计算可能出现误差,因此,判断浮点数相等用==
判断不靠谱
public class Main {
public static void main(String[] args) {
double x = 1 - 9.0 / 10;
if (x == 0.1) {
System.out.println("x is 0.1");
} else {
System.out.println("x is NOT 0.1");
}
}
}
引用类型判断内容相等要使用equals()
,注意避免NullPointerException
。
public class Main {
public static void main(String[] args) {
String s1 = "hello";
String s2 = "HELLO".toLowerCase();
System.out.println(s1);
System.out.println(s2);
if (s1.equals(s2)) {
System.out.println("s1 equals s2");
} else {
System.out.println("s1 not equals s2");
}
}
}
for each
和for
循环相比,for each
循环的变量n不再是计数器,而是直接对应到数组的每个元素。for each
循环的写法也更简洁。但是,for each
循环无法指定遍历顺序,也无法获取数组的索引。
public class Main {
public static void main(String[] args) {
int[] ns = { 1, 4, 9, 16, 25 };
for (int n : ns) {
System.out.println(n);
}
}
}
二维数组
for (int[] arr : ns) { //arr 对应每个ns[]的元素
for (int n : arr) { //n再对应arr[]中的每个元素
System.out.print(n);
System.out.print(', ');
}
System.out.println();
}
打印多维数组可以使用 Arrays.deepToString()
;
命令行参数
面向对象编程
public class Main {
public static void main(String[] args) {
City bj = new City();
bj.name = "Beijing";
bj.latitude = 39.903;
bj.longitude = 116.401;
System.out.println(bj.name);
System.out.println("location: " + bj.latitude + ", " + bj.longitude);
}
}
class City {
public String name;
public double latitude;
public double longitude;
}
定义方法
从上面的代码可以看出,定义方法的语法是:
修饰符 方法返回类型 方法名(方法参数列表) {
若干方法语句;
return 方法返回值;
}
继承
继承是面向对象编程的一种强大的代码复用方式;
Java只允许单继承,所有类最终的根类是
Object
;(可以套娃实现多继承)protected
允许子类访问父类的字段和方法;子类的构造方法可以通过
super()
调用父类的构造方法;可以安全地向上转型为更抽象的类型;
可以强制向下转型,最好借助
instanceof
判断;子类和父类的关系是is,has关系不能用继承。
用
final
修饰的类不能被继承对于一个类的实例字段,同样可以用
final
修饰。用final
修饰的字段在初始化后不能被修改。例如:javaclass Person { public final String name = "Unamed"; }
对
final
字段重新赋值会报错:jadePerson p = new Person(); p.name = "New Name"; // compile error!
可以在构造方法中初始化final字段:
class Person {
public final String name;
public Person(String name) {
this.name = name;
}
}
这种方法更为常用,因为可以保证实例一旦创建,其final
字段就不可修改
多态
成员方法
:编译看左边,执行看右边成员变量
:编译看左边,执行看左边
---为什么 成员变量
和 成员方法
的访问不一样呢? 因为 成员方法
有重写,而 成员变量
没有。
抽象类
抽象类和抽象方法必须使用 abstract关键字修饰
public abstract class 类名 {}
public abstract void eat();
抽象类中不一定有抽象方法,有抽象方法的类一定是抽象类
抽象类不能实例化
抽象类如何实例化呢?参照多态的方式,通过子类对象实例化,这叫抽象类多态
抽象类的子类
要么重写抽象类中的所有抽象方法
要么是抽象类
抽象类的成员特点
成员变量
可以是变量,也可以是常量 构造方法
有构造方法,但是不能实例化
例:
Animal a = new Animal()
那么,构造方法的作用是什么呢?s
用于子类访问父类数据的初始化
成员方法
可以有抽象方法:限定子类必须完成某些动作 也可以有非抽象方法:提高代码复用性
接口
接口用关键字
interface
修饰javapublic interface 接口名 {}
类实现接口用
implements
表示javapublic class 类名 implements 接口名 {}
接口不能实例化
接口如何实例化呢?
参照多态的方式,通过实现类对象实例化,这叫接口多态
多态的形式:具体类多态,抽象类多态,接口多态
多态的前提
有继承或者实现关系;有方法重写;有父(类/接口) 引用指向(子/实现)类对象
接口的实现类
要么重写接口中的所有抽象方法
要么是抽象类
获取网页内容
import java.io.IOException;
import java.net.URL;
import java.util.Scanner;
public class ReadingWebPage {
public static void main(String args[]) throws IOException {
//实例化URL类
URL url = new URL("http://myip.ipip.net/");
//检索指定页面的内容
Scanner sc = new Scanner(url.openStream());
//实例化StringBuffer类以保存结果
StringBuffer sb = new StringBuffer();
while(sc.hasNext()) {
sb.append(sc.next());
//System.out.println(sc.next());
}
//从字符串缓冲区对象中检索字符串
String result = sb.toString();
result = new String(result.getBytes("gbk"),"utf-8"); //转换编码格式
System.out.println(result);
//删除HTML标签
result = result.replaceAll("<[^>]*>", "");
System.out.println("Contents of the web page: "+result);
}
}
下载
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
public class Test {
/**
* 从网络Url中下载文件
*
* @param urlStr
* @param fileName
* @param savePath
* @throws IOException
*/
public static String downLoadFromUrl(String urlStr, String fileName, String savePath) {
try {
URL url = new URL(urlStr);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
// 设置超时间为3秒
conn.setConnectTimeout(3 * 1000);
// 防止屏蔽程序抓取而返回403错误
conn.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");
// 得到输入流
InputStream inputStream = conn.getInputStream();
// 获取字节数组
byte[] getData = readInputStream(inputStream);
// 文件保存位置
File saveDir = new File(savePath);
if (!saveDir.exists()) {
saveDir.mkdir();
}
File file = new File(saveDir + File.separator + fileName);
FileOutputStream fos = new FileOutputStream(file);
fos.write(getData);
if (fos != null) {
fos.close();
}
if (inputStream != null) {
inputStream.close();
}
// System.out.println("info:"+url+" download success");
return saveDir + File.separator + fileName;
} catch (Exception e) {
e.printStackTrace();
}
return "";
}
/**
* 从输入流中获取字节数组
*
* @param inputStream
* @return
* @throws IOException
*/
public static byte[] readInputStream(InputStream inputStream) throws IOException {
byte[] buffer = new byte[1024];
int len = 0;
ByteArrayOutputStream bos = new ByteArrayOutputStream();
while ((len = inputStream.read(buffer)) != -1) {
bos.write(buffer, 0, len);
}
bos.close();
return bos.toByteArray();
}
public static void main(String[] args) {
downLoadFromUrl("https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=3363295869,2467511306&fm=26&gp=0.jpg",
"1.jpg","E:\\");
}
}
执行cmd
import java.io.BufferedReader;
import java.io.InputStreamReader;
/**
* 执行windows的cmd命令工具类
* @author dufei
*
*/
public class CMDUtil {
/**
* 执行一个cmd命令
* @param cmdCommand cmd命令
* @return 命令执行结果字符串,如出现异常返回null
*/
public static String excuteCMDCommand(String cmdCommand)
{
StringBuilder stringBuilder = new StringBuilder();
Process process = null;
try {
process = Runtime.getRuntime().exec(cmdCommand);
BufferedReader bufferedReader = new BufferedReader(
new InputStreamReader(process.getInputStream(), "GBK"));
String line = null;
while((line=bufferedReader.readLine()) != null)
{
stringBuilder.append(line+"\n");
}
return stringBuilder.toString();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 执行bat文件,
* @param file bat文件路径
* @param isCloseWindow 执行完毕后是否关闭cmd窗口
* @return bat文件输出log
*/
public static String excuteBatFile(String file, boolean isCloseWindow)
{
String cmdCommand = null;
if(isCloseWindow)
{
cmdCommand = "cmd.exe /c "+file;
}else
{
cmdCommand = "cmd.exe /k "+file;
}
StringBuilder stringBuilder = new StringBuilder();
Process process = null;
try {
process = Runtime.getRuntime().exec(cmdCommand);
BufferedReader bufferedReader = new BufferedReader(
new InputStreamReader(process.getInputStream(), "GBK"));
String line = null;
while((line=bufferedReader.readLine()) != null)
{
stringBuilder.append(line+"\n");
}
return stringBuilder.toString();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 执行bat文件,新开窗口
* @param file bat文件路径
* @param isCloseWindow 执行完毕后是否关闭cmd窗口
* @return bat文件输出log
*/
public static String excuteBatFileWithNewWindow(String file, boolean isCloseWindow)
{
String cmdCommand = null;
if(isCloseWindow)
{
cmdCommand = "cmd.exe /c start"+file;
}else
{
cmdCommand = "cmd.exe /k start"+file;
}
StringBuilder stringBuilder = new StringBuilder();
Process process = null;
try {
process = Runtime.getRuntime().exec(cmdCommand);
BufferedReader bufferedReader = new BufferedReader(
new InputStreamReader(process.getInputStream(), "GBK"));
String line = null;
while((line=bufferedReader.readLine()) != null)
{
stringBuilder.append(line+"\n");
}
return stringBuilder.toString();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public static void main(String[] args) {
String cmd = "i";
String result = CMDUtil.excuteCMDCommand(cmd);
System.out.println(result);
}
}
springBoot
yml 配置文件
@Value ("${键名}")
@ConfigurationProperties(prefix="前缀") 要求类中的变量名于yml中的键名相同
mapper
@Select("select * from user where email = #{username}")
@Insert("INSERT INTO users (email, password) VALUES (#{username}, #{cipherPwd});")
参数校验
public Result register(
@RequestParam("email")
@Pattern(regexp = EMAIL_REGEX, message = "邮箱格式不正确")
String username,
@RequestParam("password")
@Pattern(regexp = PASSWORD_REGEX, message = "密码格式不正确")
String password)
指定请求参数对应的变量名
注解
字段名
如果 JSON 字段名与 Java 对象的字段名不一致,你可以使用 Jackson 的注解来解决这个问题。特别是可以使用 @JsonProperty
注解来映射 JSON 字段到 Java 字段。以下是一个示例:
假设你的 JSON 数据如下:
json{
"full_name": "John",
"user_age": 30,
"email_address": "john@example.com"
}
你可以定义一个 Java 实体类,并使用 @JsonProperty
注解来映射 JSON 字段名到 Java 字段名:
@JsonProperty("full_name")
private String name;
@JsonProperty("user_age")
private int age;
@JsonProperty("email_address")
private String email;
@Data
是 Lombok 库中的一个注解,用于自动为类生成各种常用方法,包括 getter、setter、equals、hashCode 和 toString 方法。这大大简化了 Java 类的编写,你不再需要手动编写这些方法。
@Pattern
注解用于对字符串进行正则表达式的校验。
@Digits(integer = 5, fraction = 0)
指定了必须为最多五位的整数。
@JsonIgnore
是 Jackson 库的一个注解,用于在 JSON 序列化/反序列化时忽略某个属性。
@JsonFormat
是 Jackson 库提供的一个注解,它可以用于指定 Java 对象序列化为 JSON 时的格式。
1.@JsonProperty
- 字段命名2.@JsonPropertyOrder
- 字段序列化顺序3.@JsonAlias
- 字段别名,反序列化4.@JsonIgnore
-序列化时忽略字段5.@JsonIgnoreProperties
- 序列化时忽略某些字段6.@JsonInclude
- 序列化时作用于满足条件的7.@JsonFormat
- 设置格式,如日期时间等8.@JacksonInject
- 反序列化时注入到 java 对象9.@JsonCreator && @ConstructorProperties
- 反序列化时采用的构造方法10.@JsonSerialize && @JsonDeserialize
- 自定义序列化方法11.@JsonAnyGetter && @JsonANySetter
- 序列化对map字段的处理12.@JsonNaming
- 序列化时输出格式13.staic 和 transient 字段
在反序列化时不忽略,但在序列化时忽略
@JsonIgnore
注解是Jackson库提供的,用于在JSON序列化/反序列化过程中忽略该属性,而@NotEmpty
注解是Java Bean Validation(JSR 380)提供的,用于验证该属性在处理过程中不能为空。
如果你在反序列化(即,从JSON转换为Java对象)时需要这个字段,但在序列化(即,从Java对象转换为JSON)时不希望这个字段出现,那么可以使用Jackson的@JsonInclude
和@JsonProperty
注解来分别控制序列化和反序列化的行为:
@NotEmpty
@JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
private String cxPassword;
在这段代码中,@JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
告诉Jackson在序列化时忽略这个字段(即,不将这个字段转换为JSON),但在反序列化时包含这个字段(即,从JSON转换为Java对象时,这个字段的值会被设置)。这样,你就可以在保证数据安全性的同时,满足数据验证的需求。
WRITE_ONLY:仅做反序列化操作。 READ_ONLY:仅做序列化操作。
日期格式化
例如,你可以使用 @JsonFormat
来改变日期的序列化格式:
public class Event {
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd-MM-yyyy hh:mm:ss")
private Date eventDate;
//...
}
Validation的注解
@JsonIgnore import com.fasterxml.jackson.annotation.JsonIgnore; 让springmvc把对象转换成json字符串的时候,忽略该属性,最终json字符串中就没有这个属性了
@NotNull 值不能为null
@NotEmpty 值不能为null,并且内容不能为空
@Email 满足邮箱格式
配置文件
mybatis:
configuration:
map-underscore-to-camel-case: true # 驼峰命名转换
拦截器
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("preHandle method is Running");
return true; // 返回true才会继续向下执行,返回false则取消当前请求
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("postHandle method is Running");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion method is Running");
}
}
这个拦截器的 preHandle
方法在请求处理之前被调用,如果它返回 true
,那么请求继续被处理,否则请求被取消。postHandle
方法在请求处理之后,但在视图渲染之前被调用。afterCompletion
方法在请求处理完毕之后被调用,即在视图渲染之后。
然后,你需要在你的 Spring 配置中注册这个拦截器。如果你使用的是 Java 配置,你可以通过覆盖 WebMvcConfigurer
的 addInterceptors
方法来做到这一点:
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new MyInterceptor());
}
}
自动添加参数
你可以使用 Spring 的拦截器(Interceptor)来自动添加 email
参数。拦截器可以在请求处理之前或之后添加特定的操作,这正是你需要的。
你可以创建一个拦截器,然后在 preHandle
方法中获取 email
,并将其添加到请求的属性中。然后,在你的控制器方法中,你可以使用 @RequestAttribute
注解来获取这个 email
属性。
这是一个简单的拦截器示例:
@Component
public class EmailInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
Map<String, String> map = ThreadLocalUtil.get();
String email = map.get("email");
request.setAttribute("email", email);
return true;
}
}
然后,你需要将这个拦截器添加到你的拦截器注册表中:
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Autowired
private EmailInterceptor emailInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(emailInterceptor).addPathPatterns("/cxAcct/**");
}
}
最后,在你的控制器方法中,你可以使用 @RequestAttribute
注解来获取 email
:
@PostMapping("/bind")
public Result bind(@RequestBody @Validated CxAccount account, @RequestAttribute("email") String email) {
int loginType = account.getLoginType();
String username = account.getCxUsername();
String password = account.getCxPassword();
return chaoxingService.bind(email, loginType, username, password);
}
这样,你就可以在所有的 /cxAcct
路径下的方法中自动获取 email
参数,而不需要每次都手动从 ThreadLocalUtil
中获取。